home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevphex.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  90.7 KB  |  3,392 lines

  1. /* Copyright (C) 1995, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /****************************************************************************/
  20. /*    Ghostscript printer driver for Epson Color Photo, Photo EX, Photo 700    */
  21. /****************************************************************************/
  22.  
  23. #include "gdevprn.h"
  24. #include <math.h>
  25.  
  26. /****************************************************************************/
  27. /*                                Legend                                        */
  28. /****************************************************************************/
  29.  
  30. /*
  31.  
  32. HISTORY
  33. ~~~~~~~
  34.  
  35. 8 June 1999 Zoltán Kócsi (aka Kocsonya) zoltan@bendor.com.au
  36.  
  37.     Initial revision. 
  38.     No shingling, depletion.
  39.     Colour only.
  40.     Dither matrix is blatantly copied from gslib.c.
  41.  
  42. 17 April 2000 Zoltán Kócsi
  43.  
  44.     After much play worked out a reasonably simple colour mapping
  45.     that gives fairly good results. It has some very hairy things 
  46.     in it but ot seems to work reasonably well on a variety of natural
  47.     as well as artificial images.
  48.     
  49.         
  50. LEGALISE
  51. ~~~~~~~~
  52.  
  53. The usual disclaimer applies, neither me (Zoltán Kócsi) nor 
  54. Bendor Research Pty. Ltd. assume any liability whatsoever in 
  55. relation to events arising out of or related to the use of 
  56. the software or the included documentation in any form, way 
  57. or purpose. This software is not guaranteed to work, you
  58. get it "as is" and use it for your own risk.
  59.  
  60. This code has been donated to Aladdin Enterprises, see their
  61. license for details.
  62.  
  63. CREDIT
  64. ~~~~~~
  65. This driver was written from scratch, however, I have used the 
  66. HP/BJ driver very heavily as a reference (GhostScript's documentation
  67. needs some working :-). In addition, I got some help in understanding
  68. the more arcane features of the printer by digging into the colour
  69. Epson driver and its documentation (documentation for the Photo EX 
  70. did not exist). I thank to the authors of these drivers and the 
  71. related docs. 
  72.  
  73. I do also hereby express my despising Epson, Inc. who try to enlarge 
  74. Microsoft's monopoly by witholding programming information about such 
  75. a commodity item as a printer.
  76.  
  77. KNOWN BUGS/LIMITATIONS
  78. ~~~~~~~~~~~~~~~~~~~~~~
  79. - Monochrome driver is not finished yet
  80. - The driver is not optimised for speed
  81. - The driver does not support TIFF compression
  82. - Shingling and depletion is not implemented
  83. - The colour correction and ink transfer curve are hardcoded 
  84. - The dither matrix is straight stolen from Ghostscript
  85. - The alternative error diffusion included but does not work (yet)
  86.  
  87. I plan to attend these issues later, however, I don't promise any timeframe
  88. for I have a lot else to do for bread & butter too.
  89.  
  90. PREFACE
  91. ~~~~~~~
  92. The Epson Stylus Photo EX is a colour ink-jet printer.
  93. It can handle papers up to A3. It uses 6 inks, black in one cartridge
  94. and cyan, magenta, yellow, light cyan and light magenta in an other 
  95. cartridge. The head has 32 nozzles, with 1/90" spacing. 
  96. The maximal resolution is 1440 dpi horizontal 720 dpi vertical.
  97. In 720x720 and 360x360 dpi it supports microweave. To achieve
  98. 1440x720 you must use software weaving. It has only one built-in font,
  99. namely 12pt Courier; the printer in general havily relies on the
  100. driver software. It comes with (what else ?) Windows 9x and Mac drivers.
  101.  
  102. The printer uses the ESC/P Raster protocol. This protocol is somewhat
  103. similar to the ESC/P2 one. Initially Epson refused to give any info
  104. about it. Later (unfortunately after I had already spent lot of time
  105. to reverse engineer it) they released its definition. It could be 
  106. found on their website (http://www.ercipd.com/isv/level1/6clr_98b.pdf).
  107. Alas, they removed it, so at the moment I do not know about any existing
  108. docs of the printer. 
  109. There are still a few commands which are not covered by the docs
  110. and for example the Windows driver uses them. There are others which
  111. are in the docs, saying that you can find them in other docs but you 
  112. can't. Fortunately, these commands apparently have no effect on the 
  113. printing process so this driver simply ignores them. Tricky business.
  114.  
  115. By the way, my personal experience is that Epson tech support is 
  116. a joke, or in Usenet lingvo it sucks big time - they know absolutely
  117. nothing about the product they supposed to support. Epson's webpage
  118. contains false info as well (they state that the Photo EX uses ESC/P2,
  119. which is simply not true).
  120.  
  121. This driver should in theory support the Stylus 700 and the Stylus Photo
  122. as well but I have not tested it on them.
  123.  
  124. If you think that you can get some useful info from me above of what you
  125. can find below, feel free to email me at zoltan@bendor.com.au.
  126. If you enhance the driver or find a bug *please* send me info about 
  127. it. 
  128.  
  129. DRIVER
  130. ~~~~~~
  131. The driver was written under Ghostscript 5.10.
  132. This file should contain two drivers, one for colour mode and one for B&W.
  133. The devices are "photoex" and "photoexm". The mono device driver is
  134. catered for (that is, the rendering part knows how to render for B&W)
  135. but it is not finished yet (no device structure and gray colour mapping
  136. procedures) mainly because all my B&W needs are fairly well satisfied 
  137. by our laser printer.
  138.  
  139. The driver features the following:
  140.  
  141. Supported resolutions
  142.  
  143.      360x360    Y weaving (not that micro :-) by the printer
  144.      720x720    Y microweave by the driver (quicker than the printer)
  145.     1440x720    Y and X microweave by the driver
  146.     
  147.     Resolutions other than these will result in a rangecheck error.
  148.     
  149. Papersize:
  150.     
  151.     Whatever Ghostscript supports. The printer docs say that if you load
  152.     multiple sheets of transparencies into the tray you should at least
  153.     have 30mm or 1.2" top margin. The driver always sets the smallest 
  154.     possible top margin (3mm or 0.12"), it's up to you to comply.
  155.     
  156.     In addition, the printer says that the bottom margin is at least
  157.     14mm or 0.54". I violate it by setting it to 0.5" or 12.7mm.
  158.     0.5" seems to be a common margin value for documents and you 
  159.     would hate it when the last line of your page gets printed on the
  160.     top of the next sheet ...
  161.     
  162. Options:
  163.     
  164.     -dDotSize=n
  165.     
  166.         n = 0        Let the driver choose a dotsize
  167.         n = 1        small dots
  168.         n = 2        more ink
  169.         n = 3        ink flood
  170.         n = 4        'super microdots' (whatever they are, they are *big*)
  171.         
  172.         The default is 0 which is n=1 for 1440x720, 2 for 720x720 and
  173.         3 for 360x360. Do not use large dots if you don't have to, you
  174.         will soak the paper. If you print 720x720 on normal paper, try
  175.         using n=1.
  176.         
  177.     -dRender=n
  178.     
  179.         n = 0        Floyd-Steinbeck error diffusion
  180.         n = 1        Clustered dither
  181.         n = 2        Bendor's error diffusion (experimental, do not use)
  182.         
  183.         Default is Floyd-Steinbeck error diffusion
  184.         
  185.     -dLeakage=nn
  186.     
  187.         nn is between 0 and 25. It only effects Bendor's error diffusion.
  188.         It sets the percentage of the error which is left to 'leak', that
  189.         is it is the coefficient of an exponential decay of the error.
  190.         Experiments show that it can be beneficial on image quality.
  191.         Default is 0 (no leakage).
  192.         
  193.     -dSplash=nn
  194.     
  195.         nn is between 0 and 100. It only affects Bendor's error diffusion.
  196.         The ED routine tries to take the increase of dot diameter on certain
  197.         paper types into account. 
  198.         It sets the percentage of the ink dot size increase as it splashes
  199.         onto the paper and spreads. 0 means no splashing, 100 means that 
  200.         the dot is twice as large as it should be. 
  201.         Default is 0.
  202.         
  203.     -dBinhibit=n
  204.     
  205.         If n is 1, then if black ink is deposited to a pixel, it will
  206.         inhibit the deposition of any other ink to the same pixel.
  207.         If 0, black ink may be deposited together with other inks.
  208.         Default is on (1).
  209.          
  210. ESC/P RASTER DOCS
  211. ~~~~~~~~~~~~~~~~~
  212. The parts of the ESC/P Raster protocol which I've managed to decipher, 
  213. and which are actually used in this driver can be found below.
  214. nn, mm, xx, etc. represent a single byte with a binary value in it.
  215. nnnn, xxxx etc. represent a 16-bit binary number, sent in two bytes,
  216. in little endian order (low byte first). 2-digit numbers are a single 
  217. byte in hex. Other chars are themselves.
  218. Quite a few commands are identical to the ESC/P2 commands, these are 
  219. marked with (P2).
  220.  
  221. ESC @                                (P2)    
  222.     
  223.     Resets the printer.
  224.  
  225.  
  226. ESC ( U 01 00 nn                    (P2)
  227.  
  228.     Sets the unit to 3600/nn dpi. Note that 1440 can not be set !
  229.  
  230.  
  231. ESC ( C 02 00 nnnn                    (P2)
  232.  
  233.     Sets the page (paper) length to nnnn units
  234.     
  235.  
  236. ESC ( c 04 00 bbbb tttt                (P2)
  237.  
  238.     Sets the top margin to tttt units, the bottom margin to
  239.     bbbb units. The bottom margin is measured from the top
  240.     of the page not from the bottom of the page !
  241.         
  242.     
  243. ESC    U nn                            (P2)
  244.  
  245.     Unidirectional printing
  246.     
  247.     nn
  248.     00    off
  249.     01    on
  250.     30    off (this is ASCII 0)
  251.     31    on    (this is ASCII 1)
  252.     
  253.         
  254. ESC    ( i 01 00 nn                    (P2)
  255.  
  256.     Microweave
  257.     
  258.     nn
  259.     00    off
  260.     01    on
  261.     30    off (this is ASCII 0)
  262.     31    on    (this is ASCII 1)
  263.     
  264.     Turns microweave on for 720x720 dpi printing.
  265.                 
  266. ESC r nn                            (P2)
  267.  
  268.     Select colour
  269.     
  270.     nn
  271.     01        Cyan
  272.     02        Magenta
  273.     04        Yellow
  274.     08        Black
  275.         
  276.  
  277. ESC ( G 01 00 nn                    (P2)
  278.  
  279.     Selects graphics mode:
  280.     
  281.     nn
  282.     00        Off
  283.     01        On
  284.     30        Off
  285.     31        On
  286.     
  287.     
  288. ESC ( v 02 00 dddd                    (P2)
  289.  
  290.     Advance the paper by dddd units defined by ESC ( U
  291.  
  292.  
  293. ESC . cc vv hh nn mmmm <data>        (P2)
  294.  
  295.     Sends graphics data to the printer.
  296.     
  297.     cc    Encoding mode
  298.     
  299.         00    Raw data
  300.         01    Run-length encoded data
  301.     
  302.     vv    Vertical resolution
  303.     
  304.         28      90 dpi    *interleave*
  305.         14     180 dpi    *interleave*
  306.         0a     360 dpi
  307.         05     720 dpi
  308.         
  309.     hh    Horizontal resolution
  310.     
  311.         0a     360 dpi
  312.         05     720 dpi
  313.         
  314.     nn    Number of nozzles
  315.     
  316.         It should be set to 32 (normal printing) or 1 (microweave)
  317.         
  318.     mmmm Number of collumns of data (not number of data bytes !)
  319.     
  320.     <data>
  321.     
  322.         The data should contain as many bytes as needed to fill the
  323.         mmmm * nn pixels. Data is presented horizontally, that is,
  324.         the bits of a byte will be represented by eight pixels in
  325.         a row. If the number of collumns is not an integer multiple 
  326.         of eight, then some bits from the last byte belonging to the
  327.         row will be discarded and the next row starts on a byte boundary.
  328.         If a bit in a byte is '1' ink is deposited, if '0' not.
  329.         The leftmost pixel is represented by the MSB, rightmost by LSB.
  330.         In case of raw data that's about it.
  331.         
  332.         In case of run-length encoded data, the following is done:
  333.         The first byte is a counter. If the counter is <= 127 then
  334.         the following counter+1 bytes are uncompressed data.
  335.         If the counter is >= 128 then the following single byte should
  336.         be repeated 257-counter times. 
  337.         
  338.     There are resolution restrictions:
  339.     
  340.         360x360 nozzle= 1 microweave on
  341.         360x360 nozzle=32 microweave off
  342.         720x 90 nozzle=32 microweave off
  343.         720x720    nozzle= 1 microweave on
  344.  
  345.     Other combinations are not supported.
  346.  
  347. ESC ( e 02 00 00 nn
  348.  
  349.     Sets the amount of ink spat onto the paper.
  350.     
  351.     nn
  352.     01        microdots (faint printing)
  353.     02        normal dots (not so faint printing)
  354.     03        double dots (full inking)
  355.     04        super microdots (ink is continuously dripping :-)
  356.     
  357.     Values other than that have apparently no effect.
  358.     
  359. ESC ( K 02 00 xxxx
  360.  
  361.     This command is sent by the Windows driver but it is not used
  362.     in the Epson test images. I have not found it having any effect
  363.     whatsoever. The driver does not use it. The Epson docs don't
  364.     mention it.
  365.     
  366. ESC ( r 02 00 nn mm                    
  367.     
  368.     Selects the ink according to this:
  369.  
  370.     nn mm
  371.     00 00    black
  372.     00 01    magenta
  373.     00 02    cyan
  374.     00 04    yellow
  375.     01 01    light magenta
  376.     01 02    light yellow
  377.  
  378.  
  379. ESC ( \ 04 00 xxxx llll
  380.  
  381.     Horizontal positioning of the head.
  382.     
  383.     Moves the head to the position llll times 1/xxxx inches from
  384.     the left margin. 
  385.     On the example images xxxx was always set to 1440.
  386.     I tried other values in which case the command was ignored,
  387.     so stick to 1440.
  388.  
  389.     
  390. ESC ( R ll 00 00 <text> <cc> xxxx nn .. nn 
  391. ESC 00 00 00
  392.  
  393.     This is supposedly sets the printer into 'remote' mode.
  394.     ll is the length of the <text> + 1 which consists of ASCII
  395.     characters (e.g. REMOTE1). 
  396.     <cc> is a two-character code, for example "SN" or "LD".
  397.     xxxx is the number of bytes (nn -s) which will follow.
  398.     After that there's either a new <cc> xxxx nn .. nn sequence or
  399.     the ESC 00 00 00.
  400.     I have absolutely no idea about this command and the Epson document
  401.     says that it's in an other document. It's not in that other one.
  402.     The driver does not use it. The printer does not miss it.
  403.     The Epson test images use it and the Windows driver uses it too.
  404.     They send different <cc>-s and different values for identical <cc>-s.
  405.     Go figure.
  406.     
  407. DRIVER INTERNALS
  408. ~~~~~~~~~~~~~~~~
  409. First, some comments.
  410. Anything I know about the printer can be found above. 
  411. Anything I know about Ghostscript internals (not much) can be 
  412. found in the comments in the code. I do not believe in the 'it was hard 
  413. to write, it should be hard to read' principle since I once had to 
  414. understand my own code.
  415. Therefore, the code has lots of comments in it, sometimes apparently
  416. superfluous but I find it easier to understand the program 6 months 
  417. later that way.
  418. I did not follow the Ghostscript or GNU style guide, I write code the way
  419. I like it - I'm a lazy dog :-) I use hard tabs at every 4th position,
  420. I use a *lot* of whitespace (as recommended by K&R in their original
  421. C book) and I have a formatting style similar to the K&R with the 
  422. notable exception that I do not indent variable declarations that follow 
  423. the curly. Anyway, you can run your favourite C formatter through the 
  424. source.
  425.  
  426. In addition to the above, the driver is not hand-optimised, it assumes 
  427. that it is compiled with a good optimising compiler which will handle
  428. common subexpression ellimination, move loop independent code out of
  429. the loop, transform repeated array accesses to cached pointer arithmetics
  430. and so on. The code is much more readable this way and gcc is fairly 
  431. good at doing optimisation. Feel free to hand-optimise it.
  432.  
  433. So, the driver works the following way:
  434.  
  435. When it has to render a page, first it sets up the basics such as margins
  436. and papersize and alike.
  437.  
  438. Line scheduling
  439. ---------------
  440.  
  441. Then it calls the line scheduler. To see why do we have a scheduler, you
  442. have to understand weaving. The printer head has 32 nozzles which are
  443. spaced at 8 line intervals. Therefore, it prints 32 lines at a time but they
  444. are distributed over a 256 line high area. Obviously, if you want to print 
  445. all the lines under the head, you should pass over the paper 8 times.  
  446. You can do it the obvious way:
  447. Print, move down by one line, print ... repeat 8 times then move down
  448. by 256 - 8 lines and start again. Unfortunately, this would result in
  449. stripy images due to the differences between individual nozzles.
  450. Lines 0-7 would be printed by nozzle 0, 8-15 by nozzle 1 and so on. An
  451. 8 line band has a visible height, so difference between nozzles will
  452. cause 8-line high bands to appear on the image.
  453.  
  454. The solution is 'microweave', a funny way of doing interlaced printing.
  455. Instead of moving down 1, 1, 1, 1, .. 1, 248, 1, 1 .. you move down
  456. a constant, larger amount (called a band). This amount must be chosen 
  457. in such a way that each line will be printed and preferably it will be 
  458. printed only once.
  459.  
  460. Let for example the move down amount (the band) be 31. Let's say, 
  461. in band N nozzle 31 is over line 300, in which case nozzle 30 is over
  462. line 292. We move the head down by 31 lines, then line 299 will be 
  463. under nozzle 27 and line 307 under nozzle 28.
  464. Next move, nozzle 23 will print line 298 and nozzle 24 line 306, then
  465. 19/297 20/305, 15/296 16/304, 11/295 12/303, 7/294 8/302, 3/293 4/302,
  466. 0/292 3/301 which covers the entire area between 292 and 307. 
  467. The same will apply to any other area on the page. Also note that 
  468. adjacent lines are always printed by different nozzles. 
  469. You probably have realised that line 292 was printed in the first pass
  470. and in the last one. In this case, of course, the line must not be printed 
  471. twice, one or the other pass should not deliver data to the nozzle which
  472. passes over this line.
  473.  
  474. Now there's a twist. When the horizontal resolution is 1440 dpi you have
  475. to print each line twice, first depositing all even pixels then offset
  476. the head by 1/1440" and deposit all odd pixels (the printer can only
  477. print with 720 dpi but you can initially position the head with 1440 dpi
  478. resolution). You could do it the easy way, passing over the same area 
  479. twice but you can do better. You can find a band size which will result 
  480. each line being printed twice. Instead of suppressing the double print, 
  481. you use this mechanism to print the odd and the even pixels.
  482. Now if you print one line's odd pixels, obviously, all lines belonging
  483. to the 31 other nozzles of the head will have their odd pixels printed too.
  484. Therefore, you have to keep track which lines have been printed in which
  485. phase and try to find an odd-even phase assignment to bands so that each line
  486. has both groups printed (and each group only once). 
  487. The added bonus is that even the same line will be printed by two different
  488. nozzles thus effects of nozzle differences can be decreased further.
  489.  
  490. The whole issue is further complicated with the beginning of the page and 
  491. the end of the page. When you print the first 8 lines you *must* use the
  492. print, down by 1, print ... method but then you have to switch over to the
  493. banding method. To do it well, you should minimise the number of lines which
  494. are printed out of band. This optimisation is not complex but not trivial 
  495. either. Our solution is to employ precalculated tables for the first 8 lines.
  496. (Epson's solution is not to print the 'problematic' lines at all - they
  497. warn you in the manual that at the top and bottom you may have "slight
  498. distortions". Analyzing their output reveals the reason ... ).
  499. The bottom is different. It is easier, because you are already banding, so 
  500. you can't screw up the rest of the image. On the other hand, you can't use
  501. tables because these tables would depend on the page height which you don't
  502. know a priori. Our solution is to switch to single line mode when we can 
  503. not do the banding any more and try to finish the page with the minimal 
  504. amount of passes.
  505.  
  506. So, first the driver calls the scheduler which returns a list of lines which 
  507. it dispatched to print in the current band. Then the driver checks if it has 
  508. all these lines halftoned. Since the head covers an area of 256 lines, we 
  509. have to buffer that many lines (actually, 256-7). As the head moves down, 
  510. we can flush lines which it has left and halftone the new ones.
  511.  
  512.  
  513. Colour transformations
  514. ----------------------
  515.  
  516. The next important issue is the colour transformation. The reason for doing
  517. this is that the ink is not perfect. Ideally, you have 3 inks, namely cyan
  518. magenta and yellow. Mixing these you can have all colours. Now the inks
  519. are not pure, that is the cyan ink contains some particles that have a
  520. colour other than the ideal cyan and so on. In addition, the inks are
  521. not exactly cyan, magenta and yellow. Therefore, you have to do some
  522. transformations that will map the ideal C, M, Y values to amounts of
  523. ink of the real kind. You also have a black ink. Although in theory
  524. mixing C, M, Y in equal amount will give you black, it doesn't exactly
  525. work that way. In addition, black ink is cheap compared to the colour
  526. so if you can use black, you rather use that. On top of all that, 
  527. because of other effects (ink splashing on the paper and things like that) 
  528. you have to apply some non-linear functions to get reasonable colours.
  529.  
  530. Halftoning
  531. ----------
  532.  
  533. The driver has different halftoning methods.
  534. There is the classic Floyd-Stenberg error diffusion. There is an other
  535. ED, of which I'm hammering the matrix. The matrix is larger than the
  536. FS one and IMHO results in somewhat lower halftoning noise. However,
  537. it completely screws up some flat colours so don't use it.
  538. There is also dithering, which is quick but noisy.
  539.  
  540. For any halftoning method, it is assumed that the haltoning can be 
  541. done on the 4 colours (CMYK) separately and all interdependencies are
  542. already handled. It is an optimistic assumption, however, close enough.
  543.  
  544. You can add any halftoning method you like by writing a halftoner
  545. module. A halftoner module consists of 4 functions:
  546.  
  547. - Init, which is called before halftoning starts.
  548. - Threshold, which should return a number which tells the driver how many
  549.   empty lines needed before halftoning can be stopped (i.e. for how many 
  550.   lines will a line affect halftoning of subsequent lines).
  551. - Halftone, which halftones one colour of one line
  552. - EndOfLine which is called when all colours of a scanline are halftoned,
  553.   you can do your housekeeping functions here.
  554.  
  555. For example, in the case of ED init() clears the error buffers, threshold()
  556. returns ~5 (5 empty lines are enough for the accumulated error to go to 
  557. almost zero), endofline() shuffles the error buffers and halftone() itself
  558. does the error diffusion. In case of dithering, threshold is 0 (dithering
  559. has no memory), init and endofline do nothing and halftone simply
  560. dithers a line.
  561.  
  562. A few options are available for all halftoners:
  563.  
  564. - the black is rendered first. Now this black line is presented to all
  565.   further passes. If a pixel is painted black, there's no point to
  566.   deposit any other colour on it, even if the halftoning itself would do.
  567.   Therefore, an already set black pixel can block the halftoning of colours
  568.   for that pixel. Whether this thing is activated or not is a command line
  569.   switch (default is on). Your halftoner may choose to ignore this flag.
  570.   
  571. - the intensity value of the light-cyan and light-magenta ink can be
  572.   set from the command line. My experience is that the default 127 is
  573.   good enough, but you can override it if you want to.
  574.   
  575. Apart from these features, each halftoner can have all sorts of other 
  576. switches. Currently there are switches for the Bendor ED, see the 
  577. comments in front of the BendorLine() function to see what they are.
  578.  
  579. Postprocessing
  580. --------------
  581.  
  582. After lines are halftoned, they are packed into bitstreams. If you use
  583. 1440x720 then the 2 passes for the horizontal interleave are separated.
  584. Postprocessing should also do the shingling/depletion, but it is not
  585. yet done.
  586.  
  587. Compression
  588. -----------
  589.  
  590. The driver, before it sends the data to the printer, compresses it using
  591. RLE (run-length encoding) compression. It is not very effective but still
  592. more than nothing. I have not yet ventured into using TIFF as output format,
  593. it may come later.
  594.  
  595. */
  596.  
  597. /****************************************************************************/
  598. /*                        Device specific definitions                            */
  599. /****************************************************************************/
  600.  
  601. /*
  602. *    Device limits
  603. */
  604.  
  605. #define    MAX_WIDTH    11.46            /* Maximum printable width, 8250 dots    */
  606. #define    MAX_PIXELS    8250
  607. #define    MAX_BYTES    (MAX_PIXELS+7)/8
  608.  
  609. /*
  610. *    Margins (in inch)
  611. */
  612.  
  613. #define    MARGIN_L    0.12            /* Left margin                            */
  614. #define    MARGIN_R    0.12            /* Right margin                            */
  615. #define    MARGIN_T    0.12            /* Top margin                            */
  616. #define    MARGIN_B    0.50            /* Bottom margin (should be 0.54 !)        */
  617.  
  618. /*
  619. *    We default to 720x720 dpi
  620. */
  621.  
  622. #define    Y_DPI        720                /* Default vertical resolution    [dpi]    */
  623. #define    X_DPI        720                /* Default horizontal resolution [dpi]    */
  624.  
  625. /*
  626. *    Encoding of resolutions. Does *not* work with 1440 dpi !
  627. */
  628.  
  629. #define    RESCODE( x )    (3600/(x))
  630.  
  631. /*
  632. *    The device has 6 different inks
  633. */
  634.  
  635. #define    DCOLN            6
  636.  
  637. /*
  638. *    Device colour codes
  639. *    CAVEAT: if you change them change the SendColour() procedure too !
  640. */
  641.  
  642. #define    DEV_BLACK        0
  643. #define    DEV_CYAN        1
  644. #define    DEV_MAGENTA        2
  645. #define    DEV_YELLOW        3
  646. #define    DEV_LCYAN        4
  647. #define    DEV_LMAGENTA    5
  648.  
  649. /*
  650. *    The head has 32 nozzles, with 8 x 1/720" spacing
  651. */
  652.  
  653. #define    NOZZLES            32
  654. #define    HEAD_SPACING    8
  655.  
  656. /*
  657. *    Some ASCII control characters
  658. */
  659.  
  660. #define    CR                13            /* Carriage return                        */
  661. #define    FF                12            /* Form feed                            */
  662. #define    ESC                "\033"        /* Escape                                */
  663.  
  664. /****************************************************************************/
  665. /*                        Internally used definitions                            */
  666. /****************************************************************************/
  667.  
  668. #ifndef    TRUE
  669. #define    TRUE    1
  670. #endif
  671.  
  672. #ifndef    FALSE
  673. #define    FALSE    0
  674. #endif
  675.  
  676. /*
  677. *    Since the printer is CMYK, we use 4 colours internally
  678. */
  679.  
  680. #define    ICOLN            4
  681.  
  682. /*
  683. *    This is the maximum number of error lines needed by any 
  684. *    currently implemented rendering function.
  685. *    If you need more, increase it.
  686. */
  687.  
  688. #define    MAX_ED_LINES    3
  689.  
  690. /*
  691. *    If this is defined to !0 then we use Adobe's CMYK -> RGB mapping, 
  692. *    Ghostscript's otherwise. Ghostscript claims that their mapping
  693. *    is better. The mapping of CMYK to RGB according to Adobe is:
  694. *    
  695. *        R = 1.0 - min( 1.0, C + K )
  696. *        G = 1.0 - min( 1.0, M + K )
  697. *        B = 1.0 - min( 1.0, Y + K )
  698. *
  699. *    while Ghostscript uses this:
  700. *    
  701. *        R = ( 1.0 - C ) * ( 1.0 - K )
  702. *        G = ( 1.0 - M ) * ( 1.0 - K )
  703. *        B = ( 1.0 - Y ) * ( 1.0 - K )
  704. */
  705.  
  706. #define    MAP_RGB_ADOBE    0
  707.  
  708. /*
  709. *    We store a CMYK value in a 32 bit entity, each component being 8 bit.
  710. *    These macros pack and unpack these blocks.
  711. *    Ghostscript guarantees that when we get them back the unsigned long
  712. *    will be placed in memory in a big-endian format (regardless of the
  713. *    actual architecture it's running on), so we declare the colour offsets
  714. *    accordingly.
  715. */
  716.  
  717. #define    OFFS_C        0
  718. #define    OFFS_M        1
  719. #define    OFFS_Y        2
  720. #define    OFFS_K        3
  721.  
  722. #define    DECOMPOSE_CMYK( index, c, m, y, k ) \
  723.     {                                        \
  724.         (k) = (index) & 255;                \
  725.         (y) = ( (index) >> 8 ) & 255;        \
  726.         (m) = ( (index) >> 16 ) & 255;        \
  727.         (c) = ( (index) >> 24 ) & 255;         \
  728.     }
  729.  
  730. #define    BUILD_CMYK( c, m, y, k ) \
  731.     ((((long)(c)&255)<<24)|(((long)(m)&255)<<16)|\
  732.     (((long)(y)&255)<<8)|((long)(k)&255))
  733.  
  734. /*
  735. *    This structure is for colour compensation
  736. */
  737.     
  738. typedef    struct {
  739.  
  740.     int        ra;                        /* Real colour angle (hue)                */
  741.     int        ia;                        /* Theoretical ink colour angle         */
  742.     int        c;                        /* Cyan component                        */
  743.     int        m;                        /* Magenta component                    */
  744.     int        y;                        /* Yellow component                        */
  745.     
  746. } CCOMP;
  747.  
  748. /*
  749. *    Our device structure has some extensions
  750. */
  751.  
  752. typedef    struct gx_photoex_device_s {
  753.  
  754.     gx_device_common;                /* This macro defines a graphics dev.    */
  755.     gx_prn_device_common;            /* This macro extends for printer dev.    */
  756.     int        shingling;                /* Shingling (multipass, overlap) mode    */
  757.     int        depletion;                /* Excess dot removal                    */
  758.     int        halftoner;                /* Rendering type                        */
  759.     int        splash;                    /* Splashing compensation factor        */
  760.     int        leakage;                /* Error leakage (percentage)            */
  761.     int        mono;                    /* Monochrome mode (black only)            */
  762.     int        pureblack;                /* Black ink blocks others                */
  763.     int        midcyan;                /* Light cyan ink value                    */
  764.     int        midmagenta;                /* Light magenta ink value                */
  765.     int        dotsize;                /* Size of the ink dot                    */
  766.  
  767. } gx_photoex_device;
  768.  
  769. /*
  770. *    These can save some typing
  771. */
  772.  
  773. typedef    gx_device            DEV;
  774. typedef    gx_device_printer    PDEV;
  775. typedef    gx_photoex_device    EDEV;
  776. typedef    gx_color_index        CINX;
  777. typedef    gx_color_value        CVAL;
  778. typedef    gs_param_list        PLIST;
  779. typedef    gs_param_name        PNAME;
  780.  
  781. /*
  782. *    How many lines do we have to think ahead
  783. */
  784.  
  785. #define    MAX_MARK        ((NOZZLES)*(HEAD_SPACING))
  786.  
  787. /*
  788. *    This structure stores a device scanline for one colour
  789. */
  790.  
  791. typedef    struct    {
  792.  
  793.     int        first;                    /* Index of the first useful byte    */
  794.     int        last;                    /* Index of the last useful byte    */
  795.     byte    data[ MAX_BYTES ];        /* Actual raw data                    */
  796.  
  797. } RAWLINE;
  798.  
  799. /*
  800. *    These definitions are used by the microweave scheduler.
  801. *    These are the band height definitions. Do not fiddle with them,
  802. *    they are the largest number with which no lines are skipped 
  803. *    and the unused nozzles in the head for each band is minimal.
  804. *    They, of course, depend on the number of nozzles in the head
  805. *    and their spacing, these numbers are for 32 and 8, respectively.
  806. */
  807.  
  808. #define    BAND_1440        13            /* Band height for 1440dpi, double scan    */
  809. #define    BAND_720        31            /* Band height for 720dpi, single scan    */
  810. #define    BAND_360        1            /* Band height for 360dpi, single scan    */
  811.  
  812. #define    NOZZLE_1440        (NOZZLES)    /* Number of nozzles used for 1440dpi    */
  813. #define    NOZZLE_720        (NOZZLES)    /* Number of nozzles used for 720dpi    */
  814. #define    NOZZLE_360        1            /* Number of nozzles used for 360dpi    */
  815.  
  816. /*
  817. *    This structure is used to generate the line scheduling data.
  818. *    Input/output refers to the scheduler I/F: input means data 
  819. *    given to the scheduler, output is what it gives back. Unspecified
  820. *    data is scheduler private.
  821. */
  822.  
  823. typedef    struct {
  824.  
  825.     int        last;                    /* Input    Last line to print            */
  826.     int        resol;                    /* Input    X Resolution                */
  827.     int        nozzle;                    /* Output    Number of nozzles            */
  828.     int        down;                    /* Output    Lines to move down            */
  829.     int        head[ NOZZLES ];        /* Output    Which lines to be sent        */
  830.     int        offset;                    /* Output    Offset line by 1/1440"        */
  831.     int        top;                    /*             Head position now            */
  832.     int        markbeg;                /*             First marked line            */
  833.     byte    mark[ MAX_MARK ];        /*             Marks already printed lines    */
  834.     
  835. } SCHEDUL;
  836.  
  837. /*
  838. *    These macros are used to access the printer device
  839. */
  840.  
  841. #define    SendByte( s, x )    fputc( (x), (s) )
  842.  
  843. #define    SendWord( s, x )    SendByte((s), (x) & 255); \
  844.                             SendByte((s), ((x) >> 8 ) & 255);
  845.  
  846. /*
  847. *    This structure stores all the data during rendering
  848. */
  849.  
  850. typedef    struct {
  851.     
  852.     EDEV    *dev;                    /* The actual device struct            */
  853.     FILE    *stream;                /* Output stream                    */
  854.     int        yres;                    /* Y resolution                        */
  855.     int        xres;                    /* X resolution                        */
  856.     int        start;                    /* Left margin in 1/1440 inches        */    
  857.     int        width;                    /* Input data width in pixels        */
  858.     int        lines;                    /* Number of lines                    */
  859.     int        mono;                    /* Black only                        */
  860.     byte    *dbuff;                    /* Data buffer                         */
  861.     int        htone_thold;            /* Halftoner restart threshold        */
  862.     int        htone_last;                /* Last line halftoned                */
  863.     SCHEDUL    schedule;                /* Line scheduling info                */
  864.     
  865.     /* These are the error buffers for error diffusion. MAX_PIXELS*2
  866.        is needed for 1440 dpi printing. */
  867.     
  868.     short    err[ MAX_ED_LINES ][ ICOLN ][ MAX_PIXELS*2 ];
  869.     
  870.     /* Error buffer pointers. I love C :-) */
  871.     
  872.     short    ( *error[ MAX_ED_LINES ] )[ MAX_PIXELS*2 ];
  873.     
  874.     /* This stores the halftoning result for a line, 
  875.        not yet in device format. (It's CMYK 1 byte/pixel/colour) */
  876.     
  877.     byte    res[ ICOLN ][ MAX_PIXELS*2 ];
  878.     
  879.     /* This is the buffer for rendered lines, converted
  880.        to raw device data (not yet run-length encoded).
  881.        That is, it's 6 colours, 1 bit/pixel/colour.
  882.        The first index is the 1440 dpi X-weave phase. */
  883.        
  884.     RAWLINE    raw[ 2 ][ DCOLN ][ MAX_MARK ];    
  885.     
  886.     /* This buffer stores a single line of one colour,
  887.        run-length encoded, ready to send to the printer */
  888.     
  889.     byte    rle[ MAX_PIXELS * 2 ];
  890.     
  891. } RENDER;
  892.  
  893. /*
  894. *    This is the sctructure used by the actual halftoner algorithms
  895. */
  896.  
  897. typedef    struct    {
  898.     
  899.     RENDER    *render;                /* Render info, if needed                */
  900.     byte    *data;                    /* Input data                            */
  901.     int     step;                    /* Steps on input data                    */
  902.     byte    *res;                    /* Result                                */
  903.     byte    *block;                    /* Blocking data                        */
  904.     short    **err;                    /* Pointers to error buffers            */
  905.     int        lim1;                     /* Halftoning lower limit                */
  906.     int        lim2;                     /* Halftoning upper limit                */
  907.     int        mval;                     /* Level represented by 'light' colour    */
  908.     
  909. } HTONE;    
  910.  
  911. /*
  912. *    Halftoner function table
  913. */
  914.  
  915. typedef    struct {
  916.  
  917.     int        (*hthld)( RENDER *rend );
  918.     void    (*hstrt)( RENDER *rend, int line );
  919.     void    (*hteol)( RENDER *rend, int line );
  920.     void    (*htone)( HTONE *htone, int line );
  921.  
  922. } HFUNCS;
  923.  
  924. /*
  925. *    Number of known halftoning methods
  926. */
  927.  
  928. #define    MAXHTONE        3
  929.  
  930. /*
  931. *    Dither matrix size
  932. */
  933.  
  934. #define    DMATRIX_X        16
  935. #define    DMATRIX_Y        16
  936.     
  937. /****************************************************************************/
  938. /*                            Prototypes                                        */
  939. /****************************************************************************/
  940.  
  941. private int        photoex_open( gx_device *pdev );
  942. private    int        photoex_print_page( PDEV *dev, FILE *prn_stream );
  943. private    CINX    photoex_map_rgb_color( DEV *dev, CVAL r, CVAL g, CVAL b );
  944. private int        photoex_map_color_rgb( DEV *dev, CINX index, CVAL prgb[3] );
  945. private    int        photoex_get_params( DEV *dev, PLIST *plist );
  946. private    int        photoex_put_params( DEV *dev, PLIST *plist );
  947.  
  948. private int     PutInt( PLIST *plist, PNAME name, int *val,
  949.                         int minval, int maxval, int code );
  950. private    int        GetInt( PLIST *list, PNAME name, int *value, int code );
  951.  
  952. private    int        Cmy2A( int c, int m, int y );
  953.  
  954. private    void    SchedulerInit( SCHEDUL *p );
  955. private    int        ScheduleLines( SCHEDUL *p );
  956. private    void    ScheduleLeading( SCHEDUL *p );
  957. private    void    ScheduleMiddle( SCHEDUL *p );
  958. private    void    ScheduleTrailing( SCHEDUL *p );
  959. private    void    ScheduleBand( SCHEDUL *p, int mask );
  960.  
  961. private    void    RenderPage( RENDER *p );
  962. private    void    RenderLine( RENDER *p, int line );
  963. private    int        IsScanlineEmpty( RENDER *p, byte *line );
  964.  
  965. private    int        RleCompress( RAWLINE *raw, int min, int max, byte *rle_data );
  966. private    int        RleFlush( byte *first, byte *reps, byte *now, byte *out );
  967.  
  968. private    void    SendReset( FILE *stream );
  969. private    void    SendMargin( FILE *stream, int top, int bot );
  970. private    void    SendPaper( FILE *stream, int length );
  971. private    void    SendGmode( FILE *stream, int on );
  972. private void    SendUnit( FILE *stream, int res );
  973. private    void    SendUnidir( FILE *stream, int on );
  974. private    void    SendMicro( FILE *stream, int on );
  975. private void    SendInk( FILE *stream, int x );
  976. private    void    SendDown( FILE *stream, int x );
  977. private    void    SendRight( FILE *stream, int amount );
  978. private    void    SendColour( FILE *stream, int col );
  979. private void    SendData( FILE *stream, int hres, int vres, int noz, int col );
  980. private    void    SendString( FILE *stream, const char *s );
  981.  
  982. private    void    HalftonerStart( RENDER *render, int line );
  983. private    int        HalftoneThold( RENDER *render );
  984. private    void    HalftoneLine( RENDER *render, int line, byte *data );
  985.  
  986. private    int        BendorThold( RENDER *p );
  987. private    void    BendorStart( RENDER *p, int line );
  988. private    void    BendorEol( RENDER *p, int line );
  989. private    void    BendorLine( HTONE *htone, int y );
  990.  
  991. private    int        FloydSThold( RENDER *p );
  992. private    void    FloydSStart( RENDER *p, int line );
  993. private    void    FloydSEol( RENDER *p, int line );
  994. private    void    FloydSLine( HTONE *htone, int y );
  995.  
  996. private    int        DitherThold( RENDER *p );
  997. private    void    DitherStart( RENDER *p, int line );
  998. private    void    DitherEol( RENDER *p, int line );
  999. private    void    DitherLine( HTONE *htone, int y );
  1000.  
  1001. /****************************************************************************/
  1002. /*                            Static data                                        */
  1003. /****************************************************************************/
  1004.  
  1005. /*
  1006. *    Halftoner function table
  1007. */
  1008.  
  1009. private    const HFUNCS    htable[ MAXHTONE ] = {
  1010.  
  1011.     { FloydSThold, FloydSStart, FloydSEol, FloydSLine },
  1012.     { DitherThold, DitherStart, DitherEol, DitherLine },
  1013.     { BendorThold, BendorStart, BendorEol, BendorLine }
  1014. };
  1015.  
  1016. /*
  1017. *    Define the printer procedures.
  1018. *    The definition is based on GS macros, the only real stuff that we 
  1019. *    define here are the photoex_ functions.
  1020. */
  1021.  
  1022. private    gx_device_procs photoex_device_procs = prn_color_params_procs(
  1023.  
  1024.     photoex_open,                    /* Opens the device                        */
  1025.     gdev_prn_output_page,
  1026.     gdev_prn_close,
  1027.     photoex_map_rgb_color,            /* Maps an RGB pixel to device colour    */
  1028.     photoex_map_color_rgb,            /* Maps device colour back to RGB        */
  1029.     photoex_get_params,                /* Gets device parameters                */
  1030.     photoex_put_params                /* Puts device parameters                */
  1031. );
  1032.  
  1033. /*
  1034. *    Device descriptor structure - this is what GhostScript looks
  1035. *    for and uses to identify our device.
  1036. *    Do not make it private (or static) !
  1037. */
  1038.  
  1039. gx_photoex_device far_data gs_photoex_device = {
  1040.     
  1041.     /* This is a macro that fills GS specific fields in the struct */
  1042.     
  1043.     prn_device_body(
  1044.     
  1045.         gx_photoex_device,            /* Device struct type                    */
  1046.         photoex_device_procs,         /* Procedure table                        */
  1047.         "photoex",                    /* Name of the device                    */
  1048.         DEFAULT_WIDTH_10THS,        /* Default width                        */
  1049.         DEFAULT_HEIGHT_10THS,        /* Default height                        */
  1050.         X_DPI,                         /* Vertical resolution                    */
  1051.         Y_DPI,                        /* Horizontal resolution                */
  1052.         MARGIN_L,                     /* Left margin                            */
  1053.         MARGIN_B,                     /* Bottom margin                        */
  1054.         MARGIN_R,                    /* Right margin                            */
  1055.         MARGIN_T,                     /* Top margin                            */
  1056.         ICOLN,                        /* Number of colours (4:CMYK)            */
  1057.         32,                            /* Bit per pixel for the device(!)        */
  1058.         255,                        /* Max. gray level                        */
  1059.         255,                         /* Max. colour level                    */
  1060.         256,                        /* Number of gray gradations            */
  1061.         256,                        /* Number of colour gradations            */
  1062.         photoex_print_page            /* Print page procedure                    */
  1063.     ),
  1064.     
  1065.     /* Here come our extensions */
  1066.         
  1067.     0,                                /* Shingling off, not implemented        */
  1068.     0,                                /* Depletion off, not implemented        */
  1069.     0,                                /* Dither type: FS ED                    */
  1070.     0,                                /* No splash correction                    */
  1071.     0,                                /* No leakage                            */
  1072.     0,                                /* Not monochrome                        */
  1073.     1,                                /* Colour inhibition on black            */
  1074.     127,                            /* Mid level cyan                        */
  1075.     127,                            /* Mid level magenta                    */
  1076.     0                                /* Automatic dot size setting            */
  1077. };
  1078.  
  1079. /*
  1080. *    This table contains the line scheduling table for the first 
  1081. *    few runs if we are in 720 dpi mode.
  1082. */
  1083.  
  1084. private    const int    start_720[ HEAD_SPACING ][ NOZZLES ] = {
  1085.  
  1086.     {      0,      8,     16,     24,     32,     40,     48,     56,
  1087.          64,     72,     80,     88,     96,    104,    112,    120,
  1088.         128,    136,    144,    152,    160,    168,    176,    184,
  1089.         192,    200,    208,    216,    224,    232,    240,    248 },
  1090.  
  1091.     {      1,      9,     17,     25,     33,     41,     49,     57,
  1092.          65,     73,     81,     89,     97,    105,    113,    121,
  1093.         129,    137,    145,    153,    161,    169,    177,    185,
  1094.         193,    201,    209,     -1,     -1,     -1,     -1,     -1 },
  1095.  
  1096.     {      2,     10,     18,     26,     34,     42,     50,     58,
  1097.          66,     74,     82,     90,     98,    106,    114,    122,
  1098.         130,    138,    146,    154,    162,    170,    178,     -1,
  1099.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1100.  
  1101.     {      3,     11,     19,     27,     35,     43,     51,     59,
  1102.          67,     75,     83,     91,     99,    107,    115,    123,
  1103.         131,    139,    147,     -1,     -1,     -1,     -1,     -1,
  1104.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1105.  
  1106.     {      4,     12,     20,     28,     36,     44,     52,     60,
  1107.          68,     76,     84,     92,    100,    108,    116,     -1,
  1108.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1109.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1110.  
  1111.     {      5,     13,     21,     29,     37,     45,     53,     61,
  1112.          69,     77,     85,     -1,     -1,     -1,     -1,     -1,
  1113.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1114.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1115.  
  1116.     {      6,     14,     22,     30,     38,     46,     54,     -1,
  1117.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1118.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1119.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1120.  
  1121.     {      7,     15,     23,     -1,     -1,     -1,     -1,     -1,
  1122.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1123.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1124.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 }
  1125. };
  1126.  
  1127.  
  1128. /*
  1129. *    This table contains the scheduling table for the first 
  1130. *    few lines if we are in 1440 dpi mode
  1131. */
  1132.  
  1133. private    const int    start_1440[ 2 ][ HEAD_SPACING ][ NOZZLES ] = {
  1134.   {
  1135.     {      0,      8,     16,     24,     32,     40,     48,     56,
  1136.          64,     72,     80,     88,     96,    104,    112,    120,
  1137.         128,    136,    144,    152,    160,    168,    176,    184,
  1138.         192,    200,    208,    216,    224,    232,    240,    248 },
  1139.  
  1140.     {      1,      9,     17,     25,     33,     41,     49,     57,
  1141.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1142.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1143.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1144.  
  1145.     {      2,     10,     18,     -1,     -1,     -1,     -1,     -1,
  1146.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1147.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1148.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1149.  
  1150.     {      3,     11,     19,     27,     35,     43,     51,     59,
  1151.          67,     75,     83,     -1,     -1,     -1,     -1,     -1,
  1152.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1153.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1154.  
  1155.     {      4,     12,     20,     28,     36,     44,     -1,     -1,
  1156.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1157.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1158.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1159.  
  1160.     {      5,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1161.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1162.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1163.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1164.  
  1165.     {      6,     14,     22,     30,     38,     46,     54,     62,
  1166.          70,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1167.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1168.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1169.  
  1170.     {      7,     15,     23,     31,     -1,     -1,     -1,     -1,
  1171.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1172.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1173.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1174.  
  1175.   },
  1176.   {
  1177.     {      0,      8,     16,     24,     32,     40,     48,     56,
  1178.          64,     72,     80,     88,     96,     -1,     -1,     -1,
  1179.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1180.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1181.  
  1182.     {      1,      9,     17,     25,     33,     41,     49,     57,
  1183.          65,     73,     81,     89,     97,    105,    113,    121,
  1184.         129,    137,    145,    153,    161,     -1,     -1,     -1,
  1185.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1186.  
  1187.     {      2,     10,     18,     26,     34,     42,     50,     58,
  1188.          66,     74,     82,     90,     98,    106,    114,    122,
  1189.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1190.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1191.  
  1192.     {      3,     11,     19,     27,     35,     43,     51,     59,
  1193.          67,     75,     83,     91,     99,    107,    115,    123,
  1194.         131,    139,    147,    155,    163,    171,    179,    187,
  1195.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1196.  
  1197.     {      4,     12,     20,     28,     36,     44,     52,     60,
  1198.          68,     76,     84,     92,    100,    108,    116,    124,
  1199.         132,    140,    148,     -1,     -1,     -1,     -1,     -1,
  1200.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1201.  
  1202.     {      5,     13,     21,     29,     37,     45,     53,     61,
  1203.          69,     77,     85,     93,    101,    109,     -1,     -1,
  1204.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1205.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1206.  
  1207.     {      6,     14,     22,     30,     38,     46,     54,     62,
  1208.          70,     78,     86,     94,    102,    110,    118,    126,
  1209.         134,    142,    150,    158,    166,    174,     -1,     -1,
  1210.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1211.  
  1212.     {      7,     15,     23,     31,     39,     47,     55,     63,
  1213.          71,     79,     87,     95,    103,    111,    119,    127,
  1214.         135,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
  1215.          -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
  1216.  
  1217.   }
  1218. };
  1219.  
  1220. /*
  1221. *    This is the dither matrix we use for ordered dither
  1222. *    It is a shameless copy of Ghostscript's own ...
  1223. */
  1224.  
  1225. private    byte    dmatrix[ DMATRIX_Y ][ DMATRIX_X ] = {
  1226.     {
  1227.         0x0e, 0x8e, 0x2e, 0xae, 0x06, 0x86, 0x26, 0xa6,
  1228.         0x0c, 0x8c, 0x2c, 0xac, 0x04, 0x84, 0x24, 0xa4
  1229.     },
  1230.     {
  1231.         0xce, 0x4e, 0xee, 0x6e, 0xc6, 0x46, 0xe6, 0x66,
  1232.         0xcc, 0x4c, 0xec, 0x6c, 0xc4, 0x44, 0xe4, 0x64
  1233.     },
  1234.     {
  1235.         0x3e, 0xbe, 0x1e, 0x9e, 0x36, 0xb6, 0x16, 0x96,
  1236.         0x3c, 0xbc, 0x1c, 0x9c, 0x34, 0xb4, 0x14, 0x94
  1237.     },
  1238.     {
  1239.         0xfe, 0x7e, 0xde, 0x5e, 0xf6, 0x76, 0xd6, 0x56,
  1240.         0xfc, 0x7c, 0xdc, 0x5c, 0xf4, 0x74, 0xd4, 0x54
  1241.     },
  1242.     {
  1243.         0x01, 0x81, 0x21, 0xa1, 0x09, 0x89, 0x29, 0xa9,
  1244.         0x03, 0x83, 0x23, 0xa3, 0x0b, 0x8b, 0x2b, 0xab
  1245.     },
  1246.     {
  1247.         0xc1, 0x41, 0xe1, 0x61, 0xc9, 0x49, 0xe9, 0x69,
  1248.         0xc3, 0x43, 0xe3, 0x63, 0xcb, 0x4b, 0xeb, 0x6b
  1249.     },
  1250.     {
  1251.         0x31, 0xb1, 0x11, 0x91, 0x39, 0xb9, 0x19, 0x99,
  1252.         0x33, 0xb3, 0x13, 0x93, 0x3b, 0xbb, 0x1b, 0x9b
  1253.     },
  1254.     {
  1255.         0xf1, 0x71, 0xd1, 0x51, 0xf9, 0x79, 0xd9, 0x59,
  1256.         0xf3, 0x73, 0xd3, 0x53, 0xfb, 0x7b, 0xdb, 0x5b
  1257.     },
  1258.     {
  1259.         0x0d, 0x8d, 0x2d, 0xad, 0x05, 0x85, 0x25, 0xa5,
  1260.         0x0f, 0x8f, 0x2f, 0xaf, 0x07, 0x87, 0x27, 0xa7
  1261.     },
  1262.     {
  1263.         0xcd, 0x4d, 0xed, 0x6d, 0xc5, 0x45, 0xe5, 0x65,
  1264.         0xcf, 0x4f, 0xef, 0x6f, 0xc7, 0x47, 0xe7, 0x67
  1265.     },
  1266.     {
  1267.         0x3d, 0xbd, 0x1d, 0x9d, 0x35, 0xb5, 0x15, 0x95,
  1268.         0x3f, 0xbf, 0x1f, 0x9f, 0x37, 0xb7, 0x17, 0x97
  1269.     },
  1270.     {
  1271.         0xfd, 0x7d, 0xdd, 0x5d, 0xf5, 0x75, 0xd5, 0x55,
  1272.         0xff, 0x7f, 0xdf, 0x5f, 0xf7, 0x77, 0xd7, 0x57
  1273.     },
  1274.     {
  1275.         0x02, 0x82, 0x22, 0xa2, 0x0a, 0x8a, 0x2a, 0xaa,
  1276.         0x01, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8
  1277.     },
  1278.     {
  1279.         0xc2, 0x42, 0xe2, 0x62, 0xca, 0x4a, 0xea, 0x6a,
  1280.         0xc0, 0x40, 0xe0, 0x60, 0xc8, 0x48, 0xe8, 0x68
  1281.     },
  1282.     {
  1283.         0x32, 0xb2, 0x12, 0x92, 0x3a, 0xba, 0x1a, 0x9a,
  1284.         0x30, 0xb0, 0x10, 0x90, 0x38, 0xb8, 0x18, 0x98
  1285.     },
  1286.     {
  1287.         0xf2, 0x72, 0xd2, 0x52, 0xfa, 0x7a, 0xda, 0x5a,
  1288.         0xf0, 0x70, 0xd0, 0x50, 0xf8, 0x78, 0xd8, 0x58
  1289.     }
  1290. };
  1291.  
  1292. /*
  1293. *    This is the (minimalistic) colour compensation table
  1294. */
  1295.  
  1296. static    CCOMP    ctable[] = {
  1297.  
  1298.     { -255, -255,   0,   0, 255 },        // same as green
  1299.     {  102,    0, 255,   0,   0 },        // cyan
  1300.     {  255,  255, 255, 255,   0 },        // blue
  1301.     {  560,  512,   0, 255,   0 },        // magenta
  1302.     {  765,  765,   0, 255, 255 },        // red
  1303.     { 1045, 1020,   0,   0, 255 },        // yellow
  1304.     { 1275, 1275, 255,   0, 255 },        // green
  1305.     { 1632, 1530, 255,   0,   0 }        // same as cyan
  1306. };
  1307.  
  1308. /*
  1309. *    This is the ink transfer function.
  1310. *    We use only one for all inks, this may be wrong.
  1311. */
  1312.  
  1313. static const unsigned char    xtrans[ 256 ] = {
  1314.  
  1315.       0,   0,   0,   0,   0,   0,   0,   0,   
  1316.       0,   0,   0,   0,   0,   0,   0,   0, 
  1317.       0,   0,   0,   0,   0,   0,   0,   0,   
  1318.       0,   0,   0,   0,   0,   0,   0,   0, 
  1319.       0,   0,   0,   0,   1,   1,   1,   1,   
  1320.       1,   1,   1,   1,   1,   1,   1,   1, 
  1321.       1,   1,   1,   1,   2,   2,   2,   2,   
  1322.       2,   2,   2,   2,   2,   2,   3,   3, 
  1323.       3,   3,   3,   3,   3,   4,   4,   4,   
  1324.       4,   4,   4,   5,   5,   5,   5,   5, 
  1325.       6,   6,   6,   6,   6,   7,   7,   7,   
  1326.       7,   8,   8,   8,   8,   9,   9,   9, 
  1327.      10,  10,  10,  11,  11,  11,  12,  12,  
  1328.      12,  13,  13,  13,  14,  14,  14,  15, 
  1329.      15,  16,  16,  17,  17,  17,  18,  18,  
  1330.      19,  19,  20,  20,  21,  21,  22,  22, 
  1331.      23,  23,  24,  24,  25,  26,  26,  27,  
  1332.      27,  28,  29,  29,  30,  30,  31,  32, 
  1333.      32,  33,  34,  34,  35,  36,  37,  37,  
  1334.      38,  39,  40,  40,  41,  42,  43,  44, 
  1335.      44,  45,  46,  47,  48,  49,  50,  51,  
  1336.      51,  52,  53,  54,  55,  56,  57,  58, 
  1337.      59,  60,  61,  62,  63,  64,  65,  67,  
  1338.      68,  69,  70,  71,  72,  73,  74,  76, 
  1339.      77,  78,  79,  80,  82,  83,  84,  86,  
  1340.      87,  88,  89,  91,  92,  94,  95,  96, 
  1341.      98,  99, 101, 102, 103, 105, 106, 108, 
  1342.     109, 111, 112, 114, 116, 117, 119, 120, 
  1343.     122, 124, 125, 127, 129, 130, 132, 134, 
  1344.     136, 137, 139, 141, 143, 145, 146, 148, 
  1345.     150, 152, 154, 156, 158, 160, 162, 164, 
  1346.     166, 168, 170, 172, 174, 176, 178, 180
  1347. };
  1348.  
  1349. /****************************************************************************/
  1350. /*                            Device opening                                    */
  1351. /****************************************************************************/
  1352.  
  1353. private int        photoex_open( DEV *pdev )
  1354. {
  1355. double    height;
  1356. double    width;
  1357. float    margins[ 4 ];                        /* L, B, R, T                    */
  1358.  
  1359.     height = pdev->height / pdev->y_pixels_per_inch;
  1360.     width  = pdev->width  / pdev->x_pixels_per_inch;
  1361.     
  1362.     margins[ 0 ] = 0.12;
  1363.     margins[ 1 ] = 0.5;
  1364.     margins[ 2 ] = 0.12;
  1365.     margins[ 3 ] = ( width > 11.46+0.12 ) ? width - (11.46+0.12) : 0.12;
  1366.     
  1367.     gx_device_set_margins( pdev, margins, true );
  1368.     return( gdev_prn_open( pdev ) );
  1369. }
  1370.  
  1371. /****************************************************************************/
  1372. /*                            Colour procedures                                */
  1373. /****************************************************************************/
  1374.  
  1375. /*
  1376. *    Map an RGB colour to device colour. 
  1377. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1378. *
  1379. *    Since we present ourselves to Ghostscript as if we were a 
  1380. *    full colour resolution RGB device, we calculate the CMYK 
  1381. *    values and pack them into the result. This depends on
  1382. *    color_index being at least 32 bit !!!
  1383. */
  1384.  
  1385. private    CINX    photoex_map_rgb_color( DEV *dev, CVAL r, CVAL g, CVAL b )
  1386. {
  1387. int        c, y, m, k;
  1388. int        a, s, f;
  1389. EDEV    *edev;
  1390. int        i;
  1391.  
  1392.     edev = (EDEV *) dev;
  1393.         
  1394.     /* White and black are treated on their own */
  1395.     
  1396.     if ( ( r & g & b ) == ( 1 << gx_color_value_bits ) - 1 ) {
  1397.     
  1398.         /* White */
  1399.         
  1400.         return( BUILD_CMYK( 0, 0, 0, 0 ) );    
  1401.     }
  1402.     
  1403.     if ( ( r | g | b ) == 0 ) {
  1404.     
  1405.         /* Black */
  1406.         
  1407.         return( BUILD_CMYK( 0, 0, 0, xtrans[ 0xff ] ) );
  1408.     }
  1409.  
  1410.     /* Map RGB to 8 bit/colour CMY */
  1411.     
  1412.     c = 255 - ( r >> ( gx_color_value_bits - 8 ) );
  1413.     m = 255 - ( g >> ( gx_color_value_bits - 8 ) );
  1414.     y = 255 - ( b >> ( gx_color_value_bits - 8 ) );
  1415.     
  1416.     k = xtrans[ min( c, min( m, y ) ) ] * 0.8; /* FIXME:empirical constant */
  1417.     c -= k;
  1418.     m -= k;
  1419.     y -= k;
  1420.     
  1421.     s = max ( c, max( y, m ) );
  1422.             
  1423.     /* Map the colour to an angle and find the relevant table range */
  1424.     
  1425.     a = Cmy2A( c, m, y );
  1426.     for ( i = 1 ; a > ctable[ i ].ra ; i++ );
  1427.  
  1428.     /* Now map c, m, y. */
  1429.     
  1430.     f = ((a - ctable[ i-1 ].ra) << 16 ) / (ctable[ i ].ra - ctable[ i-1 ].ra);
  1431.     c = (( ctable[i-1].c << 16 ) + ( ctable[i].c - ctable[i-1].c ) * f ) >> 16;
  1432.     m = (( ctable[i-1].m << 16 ) + ( ctable[i].m - ctable[i-1].m ) * f ) >> 16;
  1433.     y = (( ctable[i-1].y << 16 ) + ( ctable[i].y - ctable[i-1].y ) * f ) >> 16;
  1434.     
  1435.     s = xtrans[ s ];
  1436.     c = ( c * s ) >> 8;
  1437.     m = ( m * s ) >> 8;
  1438.     y = ( y * s ) >> 8;
  1439.     
  1440.     return( BUILD_CMYK( c, m, y, k ) );
  1441. }
  1442.  
  1443. /*
  1444. *    Map a device colour value back to RGB. 
  1445. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1446. *
  1447. *    CAVEAT:
  1448. *    This mapping is *not* the inverse of the RGB->CMYK.
  1449. *    It does not do any ink transfer compensation, colour compensation etc.
  1450. */
  1451.  
  1452. private int        photoex_map_color_rgb( DEV *dev, CINX index, CVAL prgb[3] )
  1453. {
  1454. uint    c, m, y, k;
  1455. CVAL    r, g, b;
  1456.  
  1457.     /* Let's separate the colours */
  1458.     
  1459.     DECOMPOSE_CMYK( index, c, m, y, k );
  1460.     
  1461.     k = index & 255;
  1462.     y = ( index >> 8 ) & 255;
  1463.     m = ( index >> 16 ) & 255;
  1464.     c = ( index >> 24 ) & 255;
  1465.     
  1466.     /* Depending on whether we use Adobe or Ghostscript mapping,
  1467.        calculate the colours */
  1468.            
  1469.     if ( MAP_RGB_ADOBE ) {
  1470.  
  1471.         r = gx_max_color_value * ( 1.0 - min( 1.0, (c / 255.0 + k / 255.0) ) );
  1472.         g = gx_max_color_value * ( 1.0 - min( 1.0, (m / 255.0 + k / 255.0) ) );
  1473.         b = gx_max_color_value * ( 1.0 - min( 1.0, (y / 255.0 + k / 255.0) ) );
  1474.     }
  1475.     else {
  1476.     
  1477.         r = gx_max_color_value * ( 1.0 - c / 255.0 ) * ( 1.0 - k / 255.0);
  1478.         g = gx_max_color_value * ( 1.0 - m / 255.0 ) * ( 1.0 - k / 255.0);
  1479.         b = gx_max_color_value * ( 1.0 - y / 255.0 ) * ( 1.0 - k / 255.0);
  1480.     }
  1481.     
  1482.     prgb[ 0 ] = r;
  1483.     prgb[ 1 ] = g;
  1484.     prgb[ 2 ] = b;
  1485.     
  1486.     return( 0 );
  1487. }
  1488.  
  1489. /*
  1490. *    This function maps a (c,m,y) triplet into an angle.
  1491. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1492. *
  1493. *    Angle:    0 cyan    C=255 M=  0 Y=  0 
  1494. *            255 blue    C=255 M=255 Y=  0
  1495. *            510 magenta    C=  0 M=255 Y=  0
  1496. *            765 red     C=  0 M=255 Y=255
  1497. *           1020 yellow    C=  0 M=  0 Y=255
  1498. *           1275 green   C=255 M=  0 Y=255
  1499. *           1530 cyan 
  1500. */
  1501.  
  1502. private    int        Cmy2A( int c, int m, int y )
  1503. {
  1504. int        black;
  1505. int        maxim;
  1506. int        a;
  1507.  
  1508.     /* Calculate the black level */
  1509.     
  1510.     black = min( c, min( m, y ) );
  1511.      
  1512.     /* Remove the black from the colours themselves */
  1513.     
  1514.     c -= black;
  1515.     m -= black;
  1516.     y -= black;
  1517.     
  1518.     /* If all 3 remaining colours are 0, then it is a gray: special case */
  1519.     
  1520.     if ( ! c && ! m && ! y ) return( 0 );
  1521.     
  1522.     /* Normalise the colours. At least one at most two of them is 0
  1523.        and at least one at most two of them is 255 */
  1524.     
  1525.     maxim = max( c, max( m, y ) );
  1526.     
  1527.     c = ( 255 * c ) / maxim;
  1528.     m = ( 255 * m ) / maxim;
  1529.     y = ( 255 * y ) / maxim;
  1530.     
  1531.     if ( c == 255 ) {
  1532.     
  1533.         if ( ! y )
  1534.         
  1535.             a = m;                    /* cyan - blue */
  1536.         else
  1537.             a = 1530 - y;            /* green - cyan */
  1538.     }
  1539.     else if ( m == 255 ) {
  1540.     
  1541.         if ( ! c )
  1542.             
  1543.             a = 510 + y;            /* magenta - red */
  1544.         else
  1545.             a = 510 - c;            /* blue - magenta */
  1546.     }
  1547.     else {
  1548.     
  1549.         if ( ! m )
  1550.             
  1551.             a = 1020 + c;            /* yellow - green */
  1552.         else
  1553.             a = 1020 - m;            /* red - yellow */
  1554.     }
  1555.     
  1556.     return( a );
  1557. }
  1558.  
  1559. /****************************************************************************/
  1560. /*                        Device parameter handling                            */
  1561. /****************************************************************************/
  1562.  
  1563. /*
  1564. *    Tell Ghostscript all about our extra device parameters
  1565. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1566. */
  1567.  
  1568. private    int        photoex_get_params( DEV *device, PLIST *plist )
  1569. {
  1570. int        code;
  1571. EDEV    *dev;
  1572.  
  1573.     dev  = (EDEV *) device;
  1574.     
  1575.     code = gdev_prn_get_params( device, plist );
  1576.     
  1577.     code = GetInt( plist, "Depletion",    &dev->depletion, code );
  1578.     code = GetInt( plist, "Shingling",    &dev->shingling, code );
  1579.     code = GetInt( plist, "Render",      &dev->halftoner, code );
  1580.     code = GetInt( plist, "Splash",        &dev->splash,    code );
  1581.     code = GetInt( plist, "Leakage",    &dev->leakage,   code );
  1582.     code = GetInt( plist, "Binhibit",    &dev->pureblack, code );
  1583.     code = GetInt( plist, "DotSize",    &dev->dotsize,     code );    
  1584.     return( code );
  1585. }
  1586.  
  1587. /*
  1588. *    Get all extra device-dependent parameters
  1589. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1590. */
  1591.  
  1592. private    int        photoex_put_params( DEV *device, PLIST *plist )
  1593. {
  1594. int        code;
  1595. EDEV    *dev;
  1596.  
  1597.     dev  = (EDEV *) device;
  1598.     code = 0;
  1599.     
  1600.     code = PutInt( plist, "Depletion",    &dev->depletion, 0,            2, code );
  1601.     code = PutInt( plist, "Shingling",    &dev->shingling, 0,         2, code );
  1602.     code = PutInt( plist, "Render",        &dev->halftoner, 0,MAXHTONE-1, code );
  1603.     code = PutInt( plist, "Splash",        &dev->splash,    0,           50, code );
  1604.     code = PutInt( plist, "Leakage",    &dev->leakage,   0,           25, code );
  1605.     code = PutInt( plist, "Binhibit",    &dev->pureblack, 0,            1, code );
  1606.     code = PutInt( plist, "DotSize",    &dev->dotsize,   0,            4, code );
  1607.  
  1608.     if ( code < 0 )
  1609.     
  1610.         return( code );
  1611.     else
  1612.         return( gdev_prn_put_params( device, plist ) );    
  1613. }
  1614.  
  1615. /*
  1616. *    Reads a named integer from Ghostscript
  1617. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1618. */
  1619.  
  1620. private int     PutInt( PLIST *plist, PNAME name, int *val,
  1621.                         int minval, int maxval, int code )
  1622. {
  1623. int        new;
  1624.  
  1625.     /* If code is already an error, we return it and do nothing. */
  1626.     
  1627.     if ( code ) return( code );
  1628.     
  1629.     /* Otherwise we try to read the value */
  1630.     
  1631.     new = *val;
  1632.         
  1633.     switch ( code = param_read_int( plist, name, &new ) ) {
  1634.     
  1635.         case 1:                        /* No such parameter defined, it's OK    */
  1636.         
  1637.             code = 0;
  1638.             break;
  1639.         
  1640.         case 0:                        /* We have received a value, rangecheck    */
  1641.     
  1642.             if ( minval > new || new > maxval )
  1643.             
  1644.                 param_signal_error( plist, name, gs_error_rangecheck );
  1645.             else
  1646.                 *val = new;
  1647.                 
  1648.             break;
  1649.         
  1650.         default:                    /* Error                                */
  1651.             break;
  1652.     }
  1653.     
  1654.     return( code );
  1655. }
  1656.  
  1657. /*
  1658. *    Writes a named integer to Ghostscript
  1659. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1660. */
  1661.  
  1662. private    int        GetInt( PLIST *list, PNAME name, int *value, int code )
  1663. {
  1664.     if ( code < 0 ) return( code );
  1665.     return( param_write_int( list, name, value ) );
  1666. }
  1667.  
  1668. /****************************************************************************/
  1669. /*                            Page rendering                                    */
  1670. /****************************************************************************/
  1671.  
  1672. /*
  1673. *    This is the function that Ghostscript calls to render a page
  1674. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1675. */
  1676.  
  1677. private    int        photoex_print_page( PDEV *device, FILE *stream )
  1678. {
  1679. int            pixels;                        /* Length of the line                 */
  1680. int            x;                            /* Work vars                        */
  1681. EDEV        *dev;                        /* Our device                        */
  1682. RENDER        *render;                    /* Rendering info                    */
  1683.  
  1684. int            xres, yres;
  1685. int            start, width;
  1686. int            unit;
  1687. double        psize;
  1688.  
  1689.     dev = (EDEV *) device;    
  1690.     
  1691.     /* Check if the resolution is one of the supported ones */
  1692.     
  1693.     yres = (int) dev->y_pixels_per_inch;
  1694.     xres = (int) dev->x_pixels_per_inch;
  1695.     
  1696.     if ( ! ( ( xres ==  360 && yres == 360 ) ||
  1697.              ( xres ==  720 && yres == 720 ) ||
  1698.              ( xres == 1440 && yres == 720 ) ) )
  1699.              
  1700.         return( gs_error_rangecheck );
  1701.         
  1702.     pixels = gdev_prn_raster( device ) / sizeof( long );
  1703.     psize  = device->height / device->y_pixels_per_inch;
  1704.     
  1705.     /* Check if the requested width is within device limits.
  1706.        The calculations are in 1440 dpi units. */
  1707.     
  1708.     start = 1440.0 * dev_l_margin( device );
  1709.  
  1710.     x = xres == 360 ? 4 : xres == 720 ? 2 : 1;
  1711.     
  1712.     if ( start + x * pixels > 2 * MAX_PIXELS ) {
  1713.     
  1714.         /* We're over the limit, clip width to the required level */
  1715.         
  1716.         width = ( 2 * MAX_PIXELS - start ) / x;
  1717.         
  1718.         /* It is rather inprobable that someone would set up a 
  1719.            left margin wider than the printer, still ... */
  1720.         
  1721.         if ( width <= 0 ) return( gs_error_rangecheck );
  1722.     }
  1723.     else {
  1724.     
  1725.         /* We accept the width as it is */
  1726.         
  1727.         width = pixels;
  1728.     }
  1729.     
  1730.     /* Now try to get the memory we need. It's actually quite a lot,
  1731.        since we have to cache 256 processed lines at 6kbyte each plus
  1732.        we need error buffers and stuff. All in all, we'll request
  1733.        about 1.5 ~ 2M. */
  1734.         
  1735.     if ( ! ( render = (RENDER *) gs_malloc( 1, sizeof( RENDER ), "PhotoEX" )))
  1736.         
  1737.         return_error( gs_error_VMerror );
  1738.     
  1739.     if ( ! ( render->dbuff = (byte *) gs_malloc( pixels, sizeof( long ), 
  1740.             "PhotoEX" ) ) ) {
  1741.             
  1742.         gs_free( render, 1, sizeof( RENDER ), "PhotoEX" );
  1743.         return_error( gs_error_VMerror );
  1744.     }
  1745.     
  1746.     /* We've done every possible check and preparation, now 
  1747.        do the work. Fill the rest of the structure so we can pass 
  1748.        it to the actual render routine. */
  1749.     
  1750.     render->dev        = dev;
  1751.     render->yres    = yres;
  1752.     render->xres    = xres;
  1753.     render->width    = width;
  1754.     render->lines    = dev->height;
  1755.     render->stream    = stream;        
  1756.     render->mono    = dev->mono;
  1757.     
  1758.      /* Initialise the printer */
  1759.                 
  1760.     SendReset( stream );
  1761.     SendReset( stream );
  1762.     SendGmode( stream, 1 );
  1763.     
  1764.     /* Set up units */
  1765.     
  1766.     unit = ( yres == 360 ) ? 360 : 720;
  1767.     SendUnit( stream, RESCODE( unit ) );
  1768.     
  1769.     /* Set up papersize and margins */
  1770.     
  1771.     SendPaper( stream, device->height / device->y_pixels_per_inch * unit );
  1772.     SendMargin( stream, ( psize - dev_b_margin( device ) ) * unit, 
  1773.                         dev_t_margin( device ) * unit );
  1774.  
  1775.     /* Dot size as per user setting */
  1776.     
  1777.     if ( dev->dotsize )
  1778.     
  1779.         SendInk( stream, dev->dotsize );
  1780.     else
  1781.         SendInk( stream, yres == 360 ? 3 : ( xres == 720 ? 2 : 1 ) );
  1782.     
  1783.     /* Microveawe is off, unidirectional printing on */
  1784.     
  1785.     SendMicro( stream, 0 );
  1786.     SendUnidir( stream, 1 );
  1787.     
  1788.     /* Render the page and send image data to printer */
  1789.     
  1790.     RenderPage( render );
  1791.                        
  1792.     /* Eject the paper, reset printer */
  1793.     
  1794.     SendByte( stream, FF );
  1795.     SendReset( stream );
  1796.     
  1797.     /* Release the memory and return */
  1798.     
  1799.     gs_free( render->dbuff, pixels, sizeof( long ), "PhotoEX" );
  1800.     gs_free( render, 1, sizeof( RENDER ), "PhotoEX" );
  1801.     return( 0 );
  1802. }
  1803.  
  1804. /*
  1805. *    Renders a page
  1806. *    ~~~~~~~~~~~~~~
  1807. */
  1808.  
  1809. private    void    RenderPage( RENDER *p )
  1810. {
  1811. int        last_done;                    /* The last line rendered                */
  1812. int        last_need;                    /* The largest line number we need        */
  1813. int        move_down;                    /* Amount of delayed head positioning    */
  1814. int        last_band;                    /* Indicates the last band                */
  1815. int        min, max;                    /* Min/max active bytes in a raw line    */
  1816. int        phase;                        /* 1440dpi X weave offset                */
  1817. int        i, j, l, col;
  1818.  
  1819.     p->htone_thold = HalftoneThold( p );
  1820.     p->htone_last  = -1 - p->htone_thold;
  1821.     
  1822.     p->schedule.top   = -1;
  1823.     p->schedule.resol = p->xres;
  1824.     p->schedule.last  = p->lines;
  1825.     
  1826.     last_done = -1;
  1827.     move_down = 0;
  1828.         
  1829.     do {
  1830.     
  1831.         /* Schedule the next batch of lines */
  1832.         
  1833.         last_band = ScheduleLines( &p->schedule );
  1834.         
  1835.         /* Find the largest line number we have to process and
  1836.            halftone all lines which have not yet been done */
  1837.         
  1838.         last_need = last_done;
  1839.         for ( i = NOZZLES-1 ; i >= 0 && p->schedule.head[ i ] == -1 ; i-- );
  1840.         if ( i >= 0 ) last_need = p->schedule.head[ i ];
  1841.         while ( last_need > last_done ) RenderLine( p, ++last_done );
  1842.         
  1843.         /* Now loop through the colours and build the data stream */
  1844.         
  1845.         phase = p->schedule.offset;
  1846.         
  1847.         for ( col = 0 ; col < DCOLN ; col++ ) {
  1848.         
  1849.             /* First see if we have to send any data at all */
  1850.             
  1851.             min = MAX_BYTES;
  1852.             max = 0;
  1853.                 
  1854.             for ( i = 0 ; i < NOZZLES && i < p->schedule.nozzle ; i++ ) {
  1855.             
  1856.                 if ( ( j = p->schedule.head[ i ] ) != -1 ) {
  1857.                 
  1858.                     j %= MAX_MARK;
  1859.                     
  1860.                     if ( p->raw[ phase ][ col ][ j ].first < min )
  1861.     
  1862.                         min = p->raw[ phase ][ col ][ j ].first;
  1863.                         
  1864.                     if ( p->raw[ phase ][ col ][ j ].last > max )
  1865.     
  1866.                         max = p->raw[ phase ][ col ][ j ].last;
  1867.                 }
  1868.             }
  1869.             
  1870.             if ( min <= max ) {
  1871.             
  1872.                 max++;
  1873.                 
  1874.                 /* We have to send data to the printer. If we have 
  1875.                    to position the head, do so now */
  1876.                 
  1877.                 if ( move_down ) {
  1878.                 
  1879.                     SendDown( p->stream, move_down );
  1880.                     move_down = 0;
  1881.                 }
  1882.                 
  1883.                 /* Set the desired colour */
  1884.                 
  1885.                 SendColour( p->stream, col );
  1886.                 
  1887.                 /* Move the head to the desired position */
  1888.                 
  1889.                 if ( p->xres == 360 )
  1890.                 
  1891.                     SendRight( p->stream, 4 * 8 * min );
  1892.                     
  1893.                 else if ( p->xres == 720 )
  1894.                 
  1895.                     SendRight( p->stream, 2 * 8 * min );
  1896.                 else
  1897.                     SendRight( p->stream, 8 * min + phase );
  1898.                 
  1899.                 /* Send the data */
  1900.                 
  1901.                 SendData( p->stream, p->xres, p->yres, p->schedule.nozzle, 
  1902.                           ( max-min ) * 8 );
  1903.                 
  1904.                 for ( i = 0 ; i < p->schedule.nozzle ; i++ ) {
  1905.                 
  1906.                     if ( ( j = p->schedule.head[ i ] ) == -1 ||
  1907.                          ( p->raw[ phase ][ col ][ j % MAX_MARK ].last <
  1908.                            p->raw[ phase ][ col ][ j % MAX_MARK ].first ) ) {
  1909.  
  1910.                         l = RleCompress( NULL, min, max, p->rle );
  1911.                     }
  1912.                     else {
  1913.                     
  1914.                         l = RleCompress( p->raw[ phase ][ col ] + j % MAX_MARK,
  1915.                                        min, max, p->rle );
  1916.                     }
  1917.                     
  1918.                     fwrite( p->rle, l, 1, p->stream );
  1919.                 }
  1920.                 
  1921.                 SendByte( p->stream, CR );
  1922.             }
  1923.         }
  1924.         
  1925.         /* Note the amount the head should go down before it prints the
  1926.            next band */
  1927.         
  1928.         move_down += p->schedule.down;
  1929.     
  1930.     } while    ( ! last_band );
  1931. }
  1932.  
  1933. /*
  1934. *    Render the the next scanline
  1935. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1936. *
  1937. *    If it finds a continuous sequence of empty lines, it renders
  1938. *    the first htone_thold number of them then stops calling the
  1939. *    actual rendering function (which is computationally expensive).
  1940. *    When it sees a nonempty line again, it restarts the renderer.
  1941. */
  1942.  
  1943. private    void    RenderLine( RENDER *p, int line )
  1944. {
  1945. byte    *data;
  1946. int        i;
  1947.  
  1948.     /* Get the line from Ghostscript and see if its empty */
  1949.     
  1950.     gdev_prn_get_bits( (PDEV *) p->dev, line, p->dbuff, &data );
  1951.  
  1952.     if ( IsScanlineEmpty( p, data ) ) {
  1953.     
  1954.         if ( line - p->htone_last > p->htone_thold ) {
  1955.         
  1956.             /* The line is empty and is farer from the last nonempty
  1957.                line than the threshold, no need to render it. */
  1958.                
  1959.             for ( i = 0 ; i < DCOLN ; i++ ) {
  1960.             
  1961.                 p->raw[ 0 ][ i ][ line % MAX_MARK ].first = MAX_BYTES;
  1962.                 p->raw[ 0 ][ i ][ line % MAX_MARK ].last  = 0;
  1963.                 p->raw[ 1 ][ i ][ line % MAX_MARK ].first = MAX_BYTES;
  1964.                 p->raw[ 1 ][ i ][ line % MAX_MARK ].last  = 0;
  1965.                 
  1966.             }
  1967.         }
  1968.         else {
  1969.             
  1970.             /* The line is empty but it is within the threshold, so we 
  1971.                have to render it. We do not move the index, though */
  1972.                
  1973.             HalftoneLine( p, line, data );
  1974.         }
  1975.     }
  1976.     else {
  1977.     
  1978.         /* This line is not empty */
  1979.         
  1980.         if ( line - p->htone_last >= p->htone_thold ) {
  1981.         
  1982.             /* Previous lines were empty and we have already stopped 
  1983.                rendering them. We have to restart the renderer */
  1984.                
  1985.             HalftonerStart( p, line );
  1986.         }
  1987.         
  1988.         /* Render the line and move the last active index to this line */
  1989.         
  1990.         HalftoneLine( p, line, data );
  1991.         p->htone_last = line;
  1992.     }
  1993. }
  1994.  
  1995. /*
  1996. *    This function tests if a scanline is empty
  1997. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1998. */
  1999.  
  2000. private    int        IsScanlineEmpty( RENDER *r, byte *line )
  2001. {
  2002. int        i;
  2003. long    *p;
  2004.     
  2005.     p = (long *) line;
  2006.     
  2007.     for ( i = 0 ; i < r->width ; i++ ) {
  2008.     
  2009.         if ( *p++ ) return( FALSE );
  2010.     }
  2011.     
  2012.     return( TRUE );    
  2013. }
  2014.  
  2015. /****************************************************************************/
  2016. /*                        Microweaved line scheduling                            */
  2017. /****************************************************************************/
  2018.  
  2019. /*
  2020. *    Schedule head data for the next band
  2021. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2022. *
  2023. *    This function fills the SCHEDUL structure with information
  2024. *    about what to print. The head field will contain the line numbers
  2025. *    which are assigned to the nozzles in the head. -1 means that
  2026. *    no active data is assigned to the nozzle in this band.
  2027. *    The offset field is only used for horizontal microweaving, if it
  2028. *    is set then the line should be offseted by 1/1440".
  2029. *    The down field contains the number of units which the head should
  2030. *    move down when printing of the band is finished. Other fields are
  2031. *    mainly for the routine's internal use. At the first call, however,
  2032. *    the top field should be set to -1, the resol field should be set 
  2033. *    to 360, 720 or 1440 and the last field should contain the number
  2034. *    of lines to print (that is, last + 1 :-). 
  2035. *
  2036. *    The routine returns a flag indicating if this was the last print
  2037. *    for the page.
  2038. */
  2039.     
  2040. private    int    ScheduleLines( SCHEDUL *p )
  2041. {
  2042. int        i;
  2043.  
  2044.     if ( p->top == -1 ) {
  2045.     
  2046.         /* First call, init everything, then fall through to the rest */
  2047.         
  2048.         SchedulerInit( p );
  2049.     }
  2050.     
  2051.     /* If nozzle is one, just schedule the next line and that's it.
  2052.        You can use this feature for hardware microweave at 720 dpi,
  2053.        the driver uses it for 360 dpi. */
  2054.     
  2055.     if ( p->nozzle == 1 ) {
  2056.     
  2057.         p->head[ 0 ] = p->top;
  2058.         p->down = 1;
  2059.         p->top++;
  2060.         return( p->top == p->last );
  2061.     }
  2062.     
  2063.     /* Release all expired entries in the mark array */
  2064.     
  2065.     for ( i = p->markbeg ; i < p->top ; i++ ) p->mark[ i % MAX_MARK ] = 0;
  2066.     p->markbeg = p->top;
  2067.     
  2068.     /* If top is less than the the head spacing, then create the image 
  2069.        by single steps. This will cause banding on the very top, but
  2070.        there's nothing we can do about it. We're still better than
  2071.        Epson's driver which simply ignores the first few lines,
  2072.        it does not even try to schedule them ... */
  2073.            
  2074.     if ( p->top < HEAD_SPACING ) {
  2075.     
  2076.         ScheduleLeading( p );
  2077.         return( FALSE );
  2078.     }
  2079.     
  2080.     /* See if we are almost at the end. If yes, we will advance line by
  2081.        line. */
  2082.     
  2083.     if ( p->top + p->resol + (NOZZLES) * HEAD_SPACING > p->last ) {
  2084.         
  2085.          ScheduleTrailing( p );
  2086.         
  2087.         if ( p->down )
  2088.         
  2089.             return( p->top + (NOZZLES-1) * HEAD_SPACING >= p->last );
  2090.         else
  2091.             return( FALSE );
  2092.     }
  2093.         
  2094.     /* Otherwise we're in the middle of the page, just do the
  2095.        simple banding and selecting as many lines as we can. */
  2096.  
  2097.     ScheduleMiddle( p );
  2098.     return( FALSE );
  2099. }
  2100.  
  2101. /*
  2102. *    Initialise the scheduler
  2103. *    ~~~~~~~~~~~~~~~~~~~~~~~~
  2104. */
  2105.  
  2106. private    void    SchedulerInit( SCHEDUL *p )
  2107. {
  2108. int        i;
  2109.             
  2110.     p->top = 0;
  2111.         
  2112.     switch ( p->resol ) {
  2113.         
  2114.         case 360:    
  2115.             p->offset = 0;
  2116.             p->resol  = BAND_360; 
  2117.             p->nozzle = NOZZLE_360;
  2118.             break;
  2119.             
  2120.         case 720:    
  2121.             p->offset = 0;
  2122.             p->resol  = BAND_720; 
  2123.             p->nozzle = NOZZLE_720;
  2124.             break;
  2125.             
  2126.         case 1440:    
  2127.             p->offset = 1;            /* Need to be set for the algorithm! */
  2128.             p->resol  = BAND_1440; 
  2129.             p->nozzle = NOZZLE_1440;
  2130.             break;
  2131.     }
  2132.     
  2133.     for ( i = 0 ; i < NOZZLES  ; i++ ) p->head[ i ] = -1;
  2134.     for ( i = 0 ; i < MAX_MARK ; i++ ) p->mark[ i ] = 0;
  2135.     p->markbeg = 0;
  2136. }
  2137.  
  2138. /*
  2139. *    Scheduling the first BAND lines for the image
  2140. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2141. */
  2142.  
  2143. private    void    ScheduleLeading( SCHEDUL *p )
  2144. {
  2145. int        i;
  2146.  
  2147.     if ( p->resol == BAND_720 ) {
  2148.  
  2149.         /* Copy the line scheduling data to the struct */
  2150.             
  2151.         memcpy( p->head, start_720[ p->top ], sizeof( int ) * NOZZLES );
  2152.             
  2153.         /* Mark all lines to be set */
  2154.             
  2155.         for ( i = 0 ; i < NOZZLES ; i++ )
  2156.             
  2157.             if ( p->head[ i ] != -1 ) 
  2158.                 
  2159.                 p->mark[ p->head[ i ] % MAX_MARK ] = 1;
  2160.             
  2161.         /* We move down by one line except at the end */
  2162.                 
  2163.         if ( p->top == HEAD_SPACING - 1 ) {
  2164.             
  2165.             p->down = BAND_720 - p->top;
  2166.             p->top  = BAND_720;
  2167.         }
  2168.         else {
  2169.             
  2170.             p->down = 1;
  2171.             p->top++;
  2172.         }
  2173.     }
  2174.     else {
  2175.             
  2176.         /* 1440 dpi version, two passes needed for each scanline */
  2177.                 
  2178.         if ( p->offset ) {
  2179.                         
  2180.             /* Copy the non-offseted scheduling data to the struct */
  2181.             
  2182.             memcpy( p->head, start_1440[0][p->top], sizeof( int ) * NOZZLES );
  2183.             
  2184.             /* Mark all lines to be set */
  2185.             
  2186.             for ( i = 0 ; i < NOZZLES ; i++ )
  2187.             
  2188.                 if ( p->head[ i ] != -1 )
  2189.                 
  2190.                     p->mark[ p->head[ i ] % MAX_MARK ] = 1;
  2191.             
  2192.             /* This is the non-offseted line, do not move ! */
  2193.                 
  2194.             p->offset = 0;
  2195.             p->down = 0;
  2196.         }
  2197.         else {
  2198.             
  2199.             /* Copy the non-offseted schduling data to the struct */
  2200.             
  2201.             memcpy( p->head, start_1440[1][p->top], sizeof( int ) * NOZZLES );
  2202.             
  2203.             /* Mark all lines to be set */
  2204.             
  2205.             for ( i = 0 ; i < NOZZLES ; i++ )
  2206.             
  2207.                 if ( p->head[ i ] != -1 )
  2208.     
  2209.                     p->mark[ p->head[ i ] % MAX_MARK ] |= 2;
  2210.             
  2211.             /* We move down by one line except at the end and set offset */
  2212.                 
  2213.             if ( p->top == HEAD_SPACING - 1 ) {
  2214.             
  2215.                 p->down = BAND_1440 - p->top;
  2216.                 p->top  = BAND_1440;
  2217.             }
  2218.             else {
  2219.             
  2220.                 p->down = 1;
  2221.                 p->top++;
  2222.             }
  2223.             
  2224.             p->offset = 1;
  2225.         }
  2226.     }    
  2227. }
  2228.  
  2229. /*
  2230. *    Scheduling the bulk of the image
  2231. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2232. */
  2233.  
  2234. private    void    ScheduleMiddle( SCHEDUL *p )
  2235. {
  2236. int        ph0, ph1;
  2237. int        line, mask;
  2238. int        i;
  2239.  
  2240.     if ( p->resol == BAND_720 ) {
  2241.     
  2242.         /* 720 DPI printing. See which lines should we print and
  2243.            fill the head array accordingly, then move down a band. */
  2244.         
  2245.         ScheduleBand( p, 1 );
  2246.         p->down = BAND_720;
  2247.         p->top += BAND_720;
  2248.     }
  2249.     else {
  2250.     
  2251.         /* 1440 dpi printing. This is a bit more complex than the
  2252.            720 dpi one. First, see how many lines in each phase
  2253.            has already been printed. */
  2254.         
  2255.         ph0 = ph1 = 0;
  2256.         
  2257.         for ( line = p->top, i=0 ; i < NOZZLES ; i++, line += HEAD_SPACING ) {
  2258.         
  2259.             line = p->top + i * HEAD_SPACING;
  2260.             ph0 += p->mark[ line % MAX_MARK ] & 1;
  2261.             ph1 += p->mark[ line % MAX_MARK ] & 2;
  2262.         }
  2263.         
  2264.         ph1 >>= 1;
  2265.     
  2266.         /* Choose the phase which has less lines in it. */
  2267.         
  2268.         if ( ph0 <= ph1 ) {
  2269.         
  2270.             p->offset = 0;
  2271.             mask = 1;
  2272.         }
  2273.         else {
  2274.         
  2275.             p->offset = 1;
  2276.             mask = 2;
  2277.         }
  2278.         
  2279.         /* Fill the line array and mark the phase.
  2280.            We should check here if moving down the head will leave
  2281.            any line empty, but we do not because we *know* that it
  2282.            won't - the BAND_1440 is selected by finding a value 
  2283.            which guarantees that it will cover every line. */
  2284.         
  2285.         ScheduleBand( p, mask );
  2286.         p->down = BAND_1440;
  2287.         p->top += BAND_1440;
  2288.     }
  2289. }
  2290.  
  2291. /*
  2292. *    Scheduling the last lines of the image
  2293. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2294. */
  2295.  
  2296. private    void    ScheduleTrailing( SCHEDUL *p )
  2297. {
  2298. int        mask;
  2299.  
  2300.     if ( p->down > 1 ) {
  2301.         
  2302.         /* This is the first time we came here. */
  2303.         
  2304.         p->offset = 1;
  2305.     }
  2306.     
  2307.     if ( p->resol == BAND_720 ) {
  2308.         
  2309.         p->offset = 0;
  2310.         p->down   = 1;
  2311.         mask      = 1;
  2312.     }
  2313.     else {
  2314.         
  2315.         if ( p->offset ) {
  2316.             
  2317.             p->offset = 0;
  2318.             p->down      = 0;
  2319.             mask      = 1;
  2320.         }
  2321.         else {
  2322.             
  2323.             p->offset = 1;
  2324.             p->down      = 1;
  2325.             mask      = 2;
  2326.         }
  2327.     }
  2328.     
  2329.     ScheduleBand( p, mask );
  2330.     p->top += p->down;
  2331. }
  2332.  
  2333. /*
  2334. *    Select lines from a given set
  2335. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2336. */
  2337.  
  2338. private    void    ScheduleBand( SCHEDUL *p, int mask )
  2339. {
  2340. int        i;
  2341. int        line;
  2342.  
  2343.     for ( line = p->top, i = 0 ; i < NOZZLES ; i++, line += HEAD_SPACING ) {
  2344.             
  2345.  
  2346.         if ( p->mark[ line % MAX_MARK ] & mask ) {
  2347.             
  2348.             p->head[ i ] = -1;
  2349.         }
  2350.         else {
  2351.             
  2352.             p->head[ i ] = line;
  2353.             p->mark[ line % MAX_MARK ] |= mask;
  2354.         }
  2355.     }
  2356. }
  2357.  
  2358. /****************************************************************************/
  2359. /*                        Formatting printer data                                */
  2360. /****************************************************************************/
  2361.  
  2362. /*
  2363. *    Packs a line to raw device format
  2364. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2365. *
  2366. *    Reads pixnum pixels and if the pixel is lev_on, then sets the
  2367. *    appropriate bit in the resulting datastream. The length of the
  2368. *    result is pixnum/8 (rounded up).
  2369. */
  2370.  
  2371. private    void    PackLine( byte *input, int pixnum, int lev_on, int step,
  2372.                           RAWLINE *line )
  2373. {
  2374. byte    bits;
  2375. char    *result;
  2376. int        i, j, k;
  2377.  
  2378.     result = line->data;
  2379.     line->first = MAX_PIXELS;
  2380.     line->last  = 0;
  2381.         
  2382.     for ( j = 0x80, bits = k = i = 0 ; i < pixnum ; i += step, input += step ){
  2383.     
  2384.         if ( *input == lev_on ) bits |= j;
  2385.         
  2386.         if ( ! ( j >>= 1 ) ) {
  2387.         
  2388.             if ( bits ) {
  2389.             
  2390.                 if ( line->first > k ) line->first = k;
  2391.                 if ( line->last  < k ) line->last  = k;
  2392.             }
  2393.             
  2394.             *result++ = bits;
  2395.             j          = 0x80;
  2396.             bits      = 0;
  2397.             k++;
  2398.         }
  2399.     }
  2400.     
  2401.     if ( j != 0x80 ) {
  2402.     
  2403.         *result = bits;
  2404.         
  2405.         if ( bits ) {
  2406.             
  2407.             if ( line->first > k ) line->first = k;
  2408.             if ( line->last  < k ) line->last  = k;
  2409.         }
  2410.     }
  2411. }
  2412.  
  2413. /*
  2414. *    Compresses (run-length encodes) a line
  2415. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2416. *
  2417. *    Returns the length of the RLE data.
  2418. */
  2419.                                  
  2420. private    int        RleCompress( RAWLINE *raw, int min, int max, byte *rle_data )
  2421. {
  2422. int        i, n;
  2423. byte    pbyte;
  2424. byte    *start, *rstrt;
  2425. int        length;
  2426. byte    *input;
  2427. int     len;
  2428.  
  2429.     if ( ! raw ) {
  2430.     
  2431.         /* This is an empty line */
  2432.     
  2433.         for ( n = 0, i = max - min ; i >= 129 ; i -= 129 ) {
  2434.         
  2435.             *rle_data++ = 128;
  2436.             *rle_data++ = 0;
  2437.             n += 2;
  2438.         }
  2439.         
  2440.         if ( i >= 2 ) {
  2441.         
  2442.             *rle_data++ = 257 - i;
  2443.             *rle_data++ = 0;
  2444.             n += 2;
  2445.         }
  2446.         else if ( i ) {
  2447.         
  2448.             *rle_data++ = 0;
  2449.             *rle_data++ = 0;
  2450.             n+= 2;
  2451.         }
  2452.         
  2453.         return( n );
  2454.     }
  2455.     
  2456.     /* There's data, set up encoding parameters */
  2457.     
  2458.     input = raw->data + min;
  2459.     len   = max - min;
  2460.         
  2461.     /* Create a run-length encoded version. We do it even if no pixel
  2462.        was set because it may be that this line is just part of a 
  2463.        multi-line band. */
  2464.     
  2465.     length = 0;
  2466.     start  = input;
  2467.     rstrt  = NULL;
  2468.     pbyte  = *input++;
  2469.     
  2470.     for ( i = 1 ; i < len ; i++, input++ ) {
  2471.         
  2472.         if ( *input == pbyte ) {
  2473.         
  2474.             /* This byte is identical to the previous one(s). */
  2475.             
  2476.             if ( ! rstrt ) {
  2477.             
  2478.                 /* This is the start of a new repeating sequence */
  2479.                 
  2480.                 rstrt = input - 1;
  2481.             }
  2482.         }
  2483.         else {
  2484.         
  2485.             /* Different byte than the previous one(s) */
  2486.             
  2487.             if ( rstrt ) {
  2488.             
  2489.                 /* There was a repetitive sequence. */
  2490.                 
  2491.                 if ( rstrt - input < 4 ) {
  2492.                 
  2493.                     /* For less than four bytes it isn't worth
  2494.                        to do RLE, we discard them */
  2495.                     
  2496.                     rstrt = NULL;
  2497.                 }
  2498.                 else {
  2499.                 
  2500.                     /* We must flush */
  2501.                     
  2502.                     n = RleFlush( start, rstrt, input, rle_data );
  2503.                     rle_data  += n;
  2504.                     length += n;
  2505.                     
  2506.                     /* Initialise again */
  2507.                     
  2508.                     start = rle_data;
  2509.                     rstrt = NULL;
  2510.                 }
  2511.             }                        
  2512.             
  2513.             pbyte = *rle_data;
  2514.         }
  2515.     }
  2516.     
  2517.     /* We flush whatever is left over */
  2518.     
  2519.     length += RleFlush( start, rstrt, input, rle_data );
  2520.     
  2521.     return( length );
  2522. }
  2523.             
  2524. /*
  2525. *    This function flushes the RLE encoding buffer
  2526. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2527. *
  2528. *    Assumes that it gets a nonrepetitive pattern followed by a repetitive
  2529. *    one. 'first' points to the start of the non-repetitive part.
  2530. *    'reps' points to the first byte in the repetitive sequence or it
  2531. *    may be NULL, if there were no repetitve bytes. 'now' points to
  2532. *    one after the last byte in the sequence.
  2533. *    It puts the result into 'out' and returns the number of bytes
  2534. *    written out.
  2535. *
  2536. *    There is one possible performance penalty in using this method:
  2537. *    If the repetitive sequence is n*128+1 byte long, then the last
  2538. *    byte will be written out as single byte. If the following sequence
  2539. *    has a nonrepetitive start, this byte could be combined into that
  2540. *    but it isn't. This can cause some penalty, however, we will live
  2541. *    with that for now.
  2542. */
  2543.                 
  2544. private    int        RleFlush( byte *first, byte *reps, byte *now, byte *out )
  2545. {
  2546. int        count;
  2547. int        l;
  2548.  
  2549.     if ( ! first ) return( 0 );
  2550.     
  2551.     if ( ! reps ) reps = now;
  2552.     
  2553.     count = 0;
  2554.         
  2555.     /* Write the nonrepetitve pattern first */
  2556.  
  2557.     while ( ( l = reps - first ) ) {
  2558.     
  2559.         if ( l > 128 ) {
  2560.         
  2561.             /* More than 128 consecutive bytes, write out a 128 byte chunk */
  2562.             
  2563.             *out++ = 127;
  2564.             memcpy( out, first, 128 );
  2565.             out   += 128;
  2566.             first += 128;
  2567.             count += 129;
  2568.         }
  2569.         else {
  2570.         
  2571.             /* There are not more than 128 bytes, write them into a 
  2572.                single chunk */
  2573.             
  2574.             *out++ = l - 1;
  2575.             memcpy( out, first, l );
  2576.             count += l + 1;
  2577.             first += l;
  2578.             out   += l;
  2579.         }
  2580.     }                
  2581.                     
  2582.     /* Now write the repeated pattern */
  2583.     
  2584.     while ( ( l = now - reps ) ) {
  2585.     
  2586.         if ( l > 128 ) {
  2587.         
  2588.             /* More than 128 bytes are identical, write out a
  2589.                129 byte chunk */
  2590.                
  2591.             *out++ = 128;
  2592.             *out++ = *reps;
  2593.             count += 2;
  2594.             reps  += 129;
  2595.         }
  2596.         else {
  2597.         
  2598.             if ( l == 1 ) {
  2599.             
  2600.                 /* There is only one byte left, write it out as a
  2601.                    nonrepetitive chunk */
  2602.                    
  2603.                 *out++ = 0;
  2604.                 *out++ = *reps;
  2605.                 count += 2;
  2606.                 reps++;
  2607.             }
  2608.             else {
  2609.                 
  2610.                 /* What remains is at least 2 bytes but not larger than what
  2611.                    can be written in a single chunk */
  2612.                    
  2613.                 *out++ = 257 - l;
  2614.                 *out++ = *reps;
  2615.                 count += 2;
  2616.                 reps   = now;
  2617.             }
  2618.         }
  2619.     }
  2620.     
  2621.     return( count );
  2622. }
  2623.  
  2624. /****************************************************************************/
  2625. /*        Low level procedures to send various commands to the printer        */
  2626. /****************************************************************************/
  2627.  
  2628. private    void    SendReset( FILE *stream )
  2629. {
  2630.     SendString( stream, ESC "@" );
  2631. }
  2632.  
  2633. private    void    SendMargin( FILE *stream, int top, int bot )
  2634. {
  2635.     SendString( stream, ESC "(c" );
  2636.     SendWord( stream, 4 );
  2637.     SendWord( stream, bot );
  2638.     SendWord( stream, top );
  2639. }
  2640.  
  2641. private    void    SendPaper( FILE *stream, int length )
  2642. {
  2643.     SendString( stream, ESC "(C" );
  2644.     SendWord( stream, 2 );
  2645.     SendWord( stream, length );
  2646. }
  2647.  
  2648. private    void    SendGmode( FILE *stream, int on )
  2649. {
  2650.     SendString( stream, ESC "(G" );
  2651.     SendWord( stream, 1 );
  2652.     SendByte( stream, on );
  2653. }
  2654.  
  2655. private void    SendUnit( FILE *stream, int res )
  2656. {
  2657.     SendString( stream, ESC "(U" );
  2658.     SendWord( stream, 1 );
  2659.     SendByte( stream, res );
  2660. }
  2661.  
  2662. private    void    SendUnidir( FILE *stream, int on )
  2663. {
  2664.     SendString( stream, ESC "U" );
  2665.     SendByte( stream, on );
  2666. }
  2667.  
  2668. private    void    SendMicro( FILE *stream, int on )
  2669. {
  2670.     SendString( stream, ESC "(i" );
  2671.     SendWord( stream, 1 );
  2672.     SendByte( stream, on );
  2673. }
  2674.  
  2675. private void    SendInk( FILE *stream, int x )
  2676. {
  2677.     SendString( stream, ESC "(e" );
  2678.     SendWord( stream, 2 );
  2679.     SendByte( stream, 0 );
  2680.     SendByte( stream, x );
  2681. }
  2682.  
  2683. private    void    SendDown( FILE *stream, int x )
  2684. {
  2685.     SendString( stream, ESC "(v" );
  2686.     SendWord( stream, 2 );
  2687.     SendWord( stream, x );
  2688. }
  2689.  
  2690. private    void    SendRight( FILE *stream, int amount )
  2691. {
  2692.     SendString( stream, ESC "(\\" );
  2693.     SendWord( stream, 4 );
  2694.     SendWord( stream, 1440 );
  2695.     SendWord( stream, amount );
  2696. }
  2697.  
  2698. private    void    SendColour( FILE *stream, int col )
  2699. {
  2700. static    int    ccode[] = { 0x000, 0x200, 0x100, 0x400, 0x201, 0x101 };
  2701.  
  2702.     SendString( stream, ESC "(r" );
  2703.     SendWord( stream, 2 );
  2704.     SendWord( stream, ccode[ col ] );
  2705. }
  2706.  
  2707. private void    SendData( FILE *stream, int hres, int vres, int noz, int col ) 
  2708. {
  2709.     SendString( stream, ESC "." );
  2710.     SendByte( stream, 1 );                /* Run-length encoded data */
  2711.     
  2712.     /* If we use 1 nozzle, then vertical resolution is what it is.
  2713.        Otherwise it must be set to 90 dpi */
  2714.        
  2715.     if ( noz == 1 )
  2716.     
  2717.         SendByte( stream, RESCODE( vres ) );
  2718.     else
  2719.         SendByte( stream, RESCODE( 90 ) );
  2720.  
  2721.     /* The horizontal resolution is max. 720 dpi */
  2722.     
  2723.     if ( hres > 720 )
  2724.     
  2725.         SendByte( stream, RESCODE( 720 ) );
  2726.     else
  2727.         SendByte( stream, RESCODE( hres ) );
  2728.         
  2729.     SendByte( stream, noz );
  2730.     SendWord( stream, col );
  2731. }
  2732.         
  2733. private    void    SendString( FILE *stream, const char *s )
  2734. {
  2735.     while ( *s ) SendByte( stream, *s++ );
  2736. }
  2737.  
  2738. /****************************************************************************/
  2739. /*                    Halftoning wrapper functions                            */
  2740. /****************************************************************************/
  2741.  
  2742. /*
  2743. *    Calls the start function of the choosen halftoner
  2744. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2745. */
  2746.  
  2747. private    void    HalftonerStart( RENDER *render, int line )
  2748. {
  2749.     (*(htable[ render->dev->halftoner ].hstrt))( render, line );
  2750. }
  2751.  
  2752. /*
  2753. *    Returns the restart threshold for the given halftoner
  2754. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2755. */
  2756.  
  2757. private    int        HalftoneThold( RENDER *render )
  2758. {
  2759.     return( (*(htable[ render->dev->halftoner ].hthld))( render ) );
  2760. }
  2761.  
  2762. /*
  2763. *    This function renders a line
  2764. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2765. *
  2766. *    This function has one fundamental assumption: halftoning of separate
  2767. *    colours is independent of each other.
  2768. *    
  2769. *    It calls the mono halftoner with the K, C, M, Y components.
  2770. */
  2771.  
  2772. private    void    HalftoneLine( RENDER *render, int line, byte *data )
  2773. {
  2774. void        (*htone)( HTONE *, int );
  2775. EDEV        *dev;
  2776. int            offs;
  2777. HTONE        hdata;
  2778. short        *errs[ MAX_ED_LINES ];
  2779. int            i;
  2780.  
  2781.     /* Get the rendering function */
  2782.     
  2783.     dev   = render->dev;
  2784.     htone = htable[ render->dev->halftoner ].htone;
  2785.     offs  = render->mono ? 0 : OFFS_K;
  2786.     
  2787.     if ( dev->mono ) {
  2788.     
  2789.         /* Monochrome, do only the black */
  2790.             
  2791.         for ( i = 0 ; i < MAX_ED_LINES ; i++ ) 
  2792.     
  2793.             errs[ i ] = render->error[ i ][ OFFS_K ];
  2794.         
  2795.         hdata.render = render;
  2796.         hdata.data   = data + OFFS_K;
  2797.         hdata.step     = sizeof( byte );
  2798.         hdata.res     = render->res[ OFFS_K ];
  2799.         hdata.block  = NULL;
  2800.         hdata.err     = errs;
  2801.         hdata.mval     = 255;
  2802.         
  2803.         (*htone)( &hdata, line );
  2804.     }
  2805.     else {
  2806.         
  2807.         /* Colour. D black first */
  2808.     
  2809.         for ( i = 0 ; i < MAX_ED_LINES ; i++ ) 
  2810.             
  2811.             errs[ i ] = render->error[ i ][ OFFS_K ];
  2812.         
  2813.         hdata.render = render;
  2814.         hdata.step     = sizeof( long );
  2815.         hdata.data   = data + OFFS_K;
  2816.         hdata.res     = render->res[ OFFS_K ];
  2817.         hdata.block  = NULL;
  2818.         hdata.err     = errs;
  2819.         hdata.mval     = 255;
  2820.         
  2821.         (*htone)( &hdata, line );
  2822.         
  2823.         /* Yellow has no intermediate ink. The already done black
  2824.            may inhibit it. */
  2825.     
  2826.         for ( i = 0 ; i < MAX_ED_LINES ; i++ ) 
  2827.         
  2828.             errs[ i ] = render->error[ i ][ OFFS_Y ];
  2829.             
  2830.         hdata.render = render;
  2831.         hdata.step     = sizeof( long );
  2832.         hdata.data   = data + OFFS_Y;
  2833.         hdata.res     = render->res[ OFFS_Y ];
  2834.         hdata.block  = dev->pureblack ? render->res[ OFFS_K ] : NULL;
  2835.         hdata.err     = errs;
  2836.         hdata.mval     = 255;
  2837.  
  2838.         (*htone)( &hdata, line );
  2839.     
  2840.         /* Cyan and magenta has intermediate colour ink, black may inhibit */
  2841.     
  2842.         for ( i = 0 ; i < MAX_ED_LINES ; i++ ) 
  2843.         
  2844.             errs[ i ] = render->error[ i ][ OFFS_C ];
  2845.             
  2846.         hdata.data   = data + OFFS_C;
  2847.         hdata.res     = render->res[ OFFS_C ];
  2848.         hdata.block  = dev->pureblack ? render->res[ OFFS_K ] : NULL;
  2849.         hdata.mval     = dev->midcyan;
  2850.  
  2851.         (*htone)( &hdata, line );
  2852.  
  2853.         for ( i = 0 ; i < MAX_ED_LINES ; i++ ) 
  2854.         
  2855.             errs[ i ] = render->error[ i ][ OFFS_M ];
  2856.             
  2857.         hdata.data   = data + OFFS_M;
  2858.         hdata.res     = render->res[ OFFS_M ];
  2859.         hdata.block  = dev->pureblack ? render->res[ OFFS_K ] : NULL;
  2860.         hdata.mval     = dev->midmagenta;
  2861.  
  2862.         (*htone)( &hdata, line );
  2863.     }
  2864.     
  2865.     /* Here we have create the raw device format scanlines */
  2866.     
  2867.     if ( dev->mono ) {
  2868.     
  2869.         if ( render->xres == 1440 ) {
  2870.         
  2871.             PackLine( render->res[ OFFS_K ], render->width, 255, 2, 
  2872.                       render->raw[ 0 ][ DEV_BLACK ]+ line % MAX_MARK );
  2873.                       
  2874.             PackLine( render->res[ OFFS_K ]+1, render->width-1, 255, 2, 
  2875.                       render->raw[ 1 ][ DEV_BLACK ]+ line % MAX_MARK );
  2876.         }
  2877.         else {
  2878.         
  2879.             PackLine( render->res[ OFFS_K ], render->width, 255, 1, 
  2880.                       render->raw[ 0 ][ DEV_BLACK ]+ line % MAX_MARK );
  2881.         }
  2882.     }
  2883.     else {
  2884.     
  2885.         if ( render->xres == 1440 ) {
  2886.         
  2887.             PackLine( render->res[ OFFS_K ], render->width, 255, 2, 
  2888.                       render->raw[ 0 ][ DEV_BLACK ]+ line % MAX_MARK );
  2889.                       
  2890.             PackLine( render->res[ OFFS_K ]+1, render->width-1, 255, 2, 
  2891.                       render->raw[ 1 ][ DEV_BLACK ]+ line % MAX_MARK );
  2892.                       
  2893.             PackLine( render->res[ OFFS_C ], render->width, 255, 2, 
  2894.                       render->raw[ 0 ][ DEV_CYAN ]+ line % MAX_MARK );
  2895.                       
  2896.             PackLine( render->res[ OFFS_C ]+1, render->width-1, 255, 2, 
  2897.                       render->raw[ 1 ][ DEV_CYAN ]+ line % MAX_MARK );
  2898.                       
  2899.             PackLine( render->res[ OFFS_M ], render->width, 255, 2, 
  2900.                       render->raw[ 0 ][ DEV_MAGENTA ]+ line % MAX_MARK);
  2901.                       
  2902.             PackLine( render->res[ OFFS_M ]+1, render->width-1, 255, 2, 
  2903.                       render->raw[ 1 ][ DEV_MAGENTA ]+ line % MAX_MARK);
  2904.                       
  2905.             PackLine( render->res[ OFFS_Y ], render->width, 255, 2, 
  2906.                       render->raw[ 0 ][ DEV_YELLOW ]+ line % MAX_MARK );
  2907.                       
  2908.             PackLine( render->res[ OFFS_Y ]+1, render->width-1, 255, 2, 
  2909.                       render->raw[ 1 ][ DEV_YELLOW ]+ line % MAX_MARK );
  2910.                       
  2911.             PackLine( render->res[ OFFS_C ], render->width, dev->midcyan, 
  2912.                       2, render->raw[ 0 ][ DEV_LCYAN ]+ line % MAX_MARK );
  2913.                       
  2914.             PackLine( render->res[ OFFS_C ]+1, render->width-1, dev->midcyan, 
  2915.                       2, render->raw[ 1 ][ DEV_LCYAN ]+ line % MAX_MARK );
  2916.                       
  2917.             PackLine( render->res[ OFFS_M ], render->width, dev->midmagenta, 
  2918.                       2, render->raw[0][ DEV_LMAGENTA ]+ line % MAX_MARK );
  2919.                       
  2920.             PackLine( render->res[ OFFS_M ]+1, render->width-1,dev->midmagenta,
  2921.                       2, render->raw[1][ DEV_LMAGENTA ]+ line % MAX_MARK );
  2922.         }
  2923.         else {
  2924.         
  2925.             PackLine( render->res[ OFFS_K ], render->width, 255, 1, 
  2926.                       render->raw[ 0 ][ DEV_BLACK ]+ line % MAX_MARK );
  2927.                       
  2928.             PackLine( render->res[ OFFS_C ], render->width, 255, 1, 
  2929.                       render->raw[ 0 ][ DEV_CYAN ]+ line % MAX_MARK );
  2930.                       
  2931.             PackLine( render->res[ OFFS_M ], render->width, 255, 1, 
  2932.                       render->raw[ 0 ][ DEV_MAGENTA ]+ line % MAX_MARK);
  2933.                       
  2934.             PackLine( render->res[ OFFS_Y ], render->width, 255, 1, 
  2935.                       render->raw[ 0 ][ DEV_YELLOW ]+ line % MAX_MARK );
  2936.                       
  2937.             PackLine( render->res[ OFFS_C ], render->width, dev->midcyan, 
  2938.                       1, render->raw[ 0 ][ DEV_LCYAN ]+ line % MAX_MARK );
  2939.                       
  2940.             PackLine( render->res[ OFFS_M ], render->width, dev->midmagenta, 
  2941.                       1, render->raw[0][ DEV_LMAGENTA ]+ line % MAX_MARK );
  2942.         }
  2943.     }
  2944.     
  2945.     /* Call the halftoner specific end-of-line function */
  2946.     
  2947.     (*htable[ render->dev->halftoner ].hteol)( render, line );
  2948. }
  2949.  
  2950. /****************************************************************************/
  2951. /*                    Floyd - Steinberg error diffusion                        */
  2952. /****************************************************************************/
  2953.  
  2954. /*
  2955. *    This function returns the empty range threshold
  2956. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2957. */
  2958.  
  2959. private    int        FloydSThold( RENDER *p )
  2960. {
  2961.     return( 5 );
  2962. }
  2963.  
  2964. /*
  2965. *    This function initialises the halftoner
  2966. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2967. */
  2968.  
  2969. private    void    FloydSStart( RENDER *p, int line )
  2970. {
  2971.     memset( p->err, 0, ICOLN * MAX_PIXELS*2 );
  2972.     p->error[ 0 ] = p->err[ 0 ];
  2973. }
  2974.  
  2975. /*
  2976. *    This function does the end-of-line processing
  2977. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2978. */
  2979.  
  2980. private    void    FloydSEol( RENDER *p, int line )
  2981. {
  2982.     /* Since we use single error buffering, nothing to do */
  2983. }
  2984.  
  2985. /*
  2986. *    This is the classical Floyd-Steinberg error diffusion.
  2987. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2988. *
  2989. *    The matrix is the following:
  2990. *
  2991. *          *    7/16    r
  2992. *   3/16  5/16  1/16
  2993. *
  2994. *    r is the residual (0, in theory). 
  2995. *    Absolutely nothing fancy is done here.
  2996. *
  2997. */
  2998.  
  2999. private    void   FloydSLine( HTONE *htone, int y )
  3000. {
  3001. int        x;                            /* Counts the pixels                    */
  3002. int        pixel;                        /* Current pixel value                    */
  3003. int        pixerr;                        /* Error value                            */
  3004. int        length;                        /* Number of pixels to process            */
  3005. byte    *res;                        /* Result                                */
  3006. byte    *data;                        /* Input data                            */
  3007. byte    *block;                        /* Block pixel                            */
  3008. int        lim1, lim2;                    /* Limits                                */
  3009. short    e0, e1;                        /* Propagating errors in current line    */
  3010. short    *l0;                        /* Error buffer pointer                    */
  3011.  
  3012.     length  = htone->render->width;
  3013.  
  3014.     res        = htone->res;
  3015.     data    = htone->data;
  3016.     block    = htone->block;
  3017.     
  3018.     lim1    = htone->mval / 2;
  3019.     lim2    = ( htone->mval + 256 ) / 2;
  3020.     
  3021.     l0        = htone->err[ 0 ];
  3022.     
  3023.     e0        = l0[ 1 ];
  3024.     e1        = l0[ 2 ];
  3025.     
  3026.     l0[ 1 ] = 0;
  3027.     l0[ 2 ] = 0;
  3028.         
  3029.     for ( x = 0 ; x < length ; x++ ) {
  3030.     
  3031.         /* First, clear the res byte. It is needed for the black */
  3032.         
  3033.         *res = 0;
  3034.         
  3035.         /* Add the actual error to the pixel, normalise, init, whatever. */
  3036.         
  3037.         pixel = ( ( *data << 4 ) + e0 );
  3038.         e0 = e1;
  3039.         e1 = l0[ 3 ] + ( pixel & 15 );            /* This is the residual */
  3040.         
  3041.         l0[ 3 ] = 0;
  3042.         pixel >>= 4;
  3043.         
  3044.         if ( ( block && *block ) || ( pixel < lim1 ) )
  3045.         
  3046.             *res = 0;
  3047.  
  3048.         else if ( pixel >= lim2 )
  3049.         
  3050.             *res = 255;
  3051.         else
  3052.             *res = htone->mval;
  3053.         
  3054.         /* Calculate the err */
  3055.         
  3056.         pixerr = pixel - *res;
  3057.         
  3058.         /* Diffuse the err */
  3059.     
  3060.         e0        += ( pixerr << 3 ) - pixerr;    /* 7/16        */
  3061.         l0[ 0 ] += ( pixerr << 2 ) - pixerr;    /* 3/16        */
  3062.         l0[ 1 ] += ( pixerr << 2 ) + pixerr;    /* 5/16        */
  3063.         l0[ 2 ] += pixerr;                        /* 1/16        */
  3064.                 
  3065.         /* We have done everything, move the pointers */
  3066.         
  3067.         res++;
  3068.         if ( block ) block++;
  3069.         data += htone->step;
  3070.         l0++;
  3071.     }
  3072. }
  3073.  
  3074. /****************************************************************************/
  3075. /*                            Ordered dither                                    */
  3076. /****************************************************************************/
  3077.  
  3078. /*
  3079. *    This function returns the empty range threshold
  3080. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3081. */
  3082.  
  3083. private    int        DitherThold( RENDER *p )
  3084. {
  3085.     return( 0 );
  3086. }
  3087.  
  3088. /*
  3089. *    This function initialises the halftoner
  3090. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3091. */
  3092.  
  3093. private    void    DitherStart( RENDER *p, int line )
  3094. {
  3095.     /* Nothing to initialise */
  3096. }
  3097.  
  3098. /*
  3099. *    This function does the end-of-line processing
  3100. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3101. */
  3102.  
  3103. private    void    DitherEol( RENDER *p, int line )
  3104. {
  3105.     /* Nothing to do - dithering has no memory */
  3106. }
  3107.  
  3108. /*
  3109. *    Clustered dither of a particular colour of a line
  3110. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3111. */
  3112.  
  3113. private    void   DitherLine( HTONE *htone, int y )
  3114. {
  3115. int        x;                            /* Counts the pixels                    */
  3116. int        pixel;                        /* Current pixel value                    */
  3117. int        length;                        /* Number of pixels to process            */
  3118. byte    *res;                        /* Result                                */
  3119. byte    *data;                        /* Input data                            */
  3120. byte    *block;                        /* Block pixel                            */
  3121. byte    *matrix;                    /* Dither matrix's current line            */
  3122. int        mx;                            /* Matrix index                            */
  3123. int        lval, hval;                    /* Halftoned high/low values            */
  3124.  
  3125.     length  = htone->render->width;
  3126.  
  3127.     res        = htone->res;
  3128.     data    = htone->data;
  3129.     block    = htone->block;
  3130.     
  3131.     matrix    = dmatrix[ y % DMATRIX_Y ];
  3132.         
  3133.     for ( mx = x = 0 ; x < length ; x++ ) {
  3134.     
  3135.         /* First, clear the res byte. It is needed for the black */
  3136.         
  3137.         *res = 0;
  3138.         
  3139.         /* Next, see if the pixel is above the mval */
  3140.         
  3141.         if ( ( pixel = *data ) > htone->mval ) {
  3142.         
  3143.             lval = htone->mval;
  3144.             hval = 255;
  3145.             
  3146.             if ( htone->mval == 127 )
  3147.  
  3148.                 pixel = ( ( pixel - htone->mval ) * 2 - 1 ) / 2;
  3149.             else
  3150.                 pixel = ( pixel - htone->mval ) * 255 / ( 255 - htone->mval );
  3151.         }
  3152.         else {
  3153.         
  3154.             lval = 0;
  3155.             hval = htone->mval;
  3156.             
  3157.             if ( htone->mval != 255 ) {
  3158.             
  3159.                 if ( htone->mval == 127 )
  3160.                 
  3161.                     pixel = ( pixel * 4 + 1 ) / 2;
  3162.                 else
  3163.                     pixel = pixel * 255 / htone->mval;
  3164.             }
  3165.         }
  3166.         
  3167.         if ( block && *block ) {
  3168.         
  3169.             *res = 0;
  3170.         }
  3171.         else {
  3172.         
  3173.             if ( pixel >= matrix[ mx ] )
  3174.         
  3175.                 *res = hval;
  3176.             else
  3177.                 *res = lval;
  3178.         }
  3179.         
  3180.         res++;
  3181.         if ( ++mx == DMATRIX_X ) mx = 0;
  3182.         if ( block ) block++;
  3183.         data += htone->step;
  3184.     }
  3185. }
  3186.  
  3187. /****************************************************************************/
  3188. /*                    Bendor's error diffusion                                */
  3189. /****************************************************************************/
  3190.  
  3191. /*
  3192. *    This function returns the empty range threshold
  3193. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3194. */
  3195.  
  3196. private    int        BendorThold( RENDER *p )
  3197. {
  3198.     return( 5 );
  3199. }
  3200.  
  3201. /*
  3202. *    This function initialises the halftoner
  3203. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3204. */
  3205.  
  3206. private    void    BendorStart( RENDER *p, int line )
  3207. {
  3208.     memset( p->err, 0, 2 * ICOLN * MAX_PIXELS*2 );
  3209.     p->error[ 0 ] = p->err[ 0 ];
  3210.     p->error[ 1 ] = p->err[ 1 ];
  3211. }
  3212.  
  3213. /*
  3214. *    This function does the end-of-line processing
  3215. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3216. */
  3217.  
  3218. private    void    BendorEol( RENDER *p, int line )
  3219. {
  3220. void    *x;
  3221.  
  3222.     x = p->error[ 0 ];
  3223.     p->error[ 0 ] = p->error[ 1 ];
  3224.     p->error[ 1 ] = x;
  3225. }
  3226.  
  3227. /*
  3228. *    Error diffusion of a particular colour of a line
  3229. *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3230. *
  3231. *    This is not yet finished (the matrix is bad, actually).
  3232. *
  3233. *    The matrix is the following (the normalisation factor is 1/128, 
  3234. *    '*' represents the current pixel, r is the truncation residual):
  3235. *
  3236. *                 *    20    10  r
  3237. *        8    14    20    14     8
  3238. *        4     8    10     8     4
  3239. *
  3240. *    We also try to take the splashing effect into account (the ink disperses
  3241. *    when it hits the paper so it partially covers surrounding pixels).
  3242. *    We use an other matrix for that, which is very simple:
  3243. *
  3244. *            *    3
  3245. *        2    3    2
  3246. *
  3247. *    and the normalisation factor can be set by the user. 
  3248. *    The splash matrix is only applied if we have actually deposited 
  3249. *    ink and the amount added to the errors is independent that of the 
  3250. *    actual image value, it only depends on the ink applied.
  3251. *    Of course, the ink spreads up and left as well and we could compensate
  3252. *    for this for a certain extent by keeping track of the errors caused in
  3253. *    previous pixels and lines and modifying them accordingly but it
  3254. *    would lead to a horrible code mess and it wouldn't be worth the effort.
  3255. *
  3256. *    A further enhancement that we allow the error to 'leak'. Experimental 
  3257. *    results show that with a 5-15% loss of error the image quality 
  3258. *    increases and the colour distortion remains very low. If you think
  3259. *    about it, this, in effect stops the error to spread its effect over
  3260. *    large areas but it will have almost undisturbed effect on neighbouring 
  3261. *    areas (you allow for an exponential error decay). 
  3262. *    This parameter is user definable, too.
  3263. */
  3264.  
  3265. private    void   BendorLine( HTONE *htone, int y )
  3266. {
  3267. int        x;                            /* Counts the pixels                    */
  3268. int        pixel;                        /* Current pixel value                    */
  3269. int        pixerr;                        /* Error value                            */
  3270. int        pixe14;                        /* 14 * err value                        */
  3271. int        sval;                        /* Splash correction value                */
  3272. int        splash;                        /* Splash factor                        */
  3273. int        leakage;                    /* Leakage factor                        */
  3274. int        length;                        /* Number of pixels to process            */
  3275. byte    *res;                        /* Result                                */
  3276. byte    *data;                        /* Input data                            */
  3277. byte    *block;                        /* Block pixel                            */
  3278. int        lim1, lim2;                    /* Limits                                */
  3279. short    e0, e1;                        /* Propagating errors in current line    */
  3280. short    *l0, *l1;                    /* Error buffer pointers                */
  3281.  
  3282.     splash  = htone->render->dev->splash;
  3283.     leakage = htone->render->dev->splash;
  3284.     length  = htone->render->width;
  3285.  
  3286.     res        = htone->res;
  3287.     data    = htone->data;
  3288.     block    = htone->block;
  3289.     
  3290.     lim1    = htone->mval / 2;
  3291.     lim2    = ( htone->mval + 256 ) / 2;
  3292.     
  3293.     l0        = htone->err[ 0 ];
  3294.     l1        = htone->err[ 1 ];
  3295.     
  3296.     e0        = l0[ 2 ];
  3297.     e1        = l0[ 3 ];
  3298.     
  3299.     l0[ 2 ] = 0;
  3300.     l0[ 3 ] = 0;
  3301.         
  3302.     for ( x = 0 ; x < length ; x++ ) {
  3303.     
  3304.         /* First, clear the res byte. It is needed for the black */
  3305.         
  3306.         *res = 0;
  3307.         
  3308.         /* Add the actual error to the pixel, normalise, init, whatever. */
  3309.         
  3310.         pixel = ( ( *data << 7 ) + e0 );
  3311.         e0 = e1;
  3312.         e1 = l0[ 4 ] + ( pixel & 127 );            /* This is the residual */
  3313.         
  3314.         l0[ 4 ] = 0;
  3315.         pixel >>= 7;
  3316.         
  3317.         if ( ( block && *block ) || ( pixel < lim1 ) )
  3318.         
  3319.             *res = 0;
  3320.  
  3321.         else if ( pixel >= lim2 )
  3322.         
  3323.             *res = 255;
  3324.         else
  3325.             *res = htone->mval;
  3326.         
  3327.         /* Calculate the err */
  3328.         
  3329.         pixerr = pixel - *res;
  3330.         
  3331.         /* If leakage is defined, apply it */
  3332.         
  3333.         if ( leakage ) pixerr -= ( pixerr * leakage ) / 100;
  3334.         
  3335.         /* Diffuse the err */
  3336.     
  3337.         pixerr <<= 1;                            /* Multiplier is 2    */
  3338.         pixe14 = pixerr;                        /* pixe14 now 2        */
  3339.         pixerr <<= 1;                            /* Multiplier is 4    */
  3340.         pixe14 += pixerr;                        /* pixe14 now 6        */
  3341.         
  3342.         l0[ 0 ] += pixerr;
  3343.         l0[ 4 ] += pixerr;
  3344.         
  3345.         pixerr <<= 1;                            /* Multiplier is 8    */
  3346.         pixe14 += pixerr;                        /* pixe14 now 14    */
  3347.         
  3348.         l0[ 1 ] += pixerr;
  3349.         l0[ 3 ] += pixerr;
  3350.         l1[ 0 ] += pixerr;
  3351.         l1[ 4 ] += pixerr;
  3352.         
  3353.         pixerr += pixerr >> 2;                    /* Multiplier is 10    */
  3354.         
  3355.         l0[ 2 ] += pixerr;
  3356.         e1        += pixerr;
  3357.         
  3358.         pixerr <<= 1;                            /* Multiplier is 20 */
  3359.         
  3360.         l1[ 2 ] += pixerr;
  3361.         e0        += pixerr;
  3362.         
  3363.         /* pixe14 already contains 14 * err */
  3364.         
  3365.         l1[ 1 ] += pixe14;
  3366.         l1[ 3 ] += pixe14;
  3367.         
  3368.         /* If splashing is defined, apply the splash matrix.
  3369.            The splash value is normalised to the same level as the err */
  3370.         
  3371.         if ( splash && *res ) {
  3372.         
  3373.             sval = splash * *res;                /* This is the 2x value    */
  3374.             
  3375.             l1[ 1 ] -= sval;
  3376.             l1[ 3 ] -= sval;
  3377.             
  3378.             sval += sval >> 1;                    /* This represents 3x    */
  3379.             
  3380.             e0        -= sval;
  3381.             l1[ 2 ] -= sval;
  3382.         }
  3383.         
  3384.         /* We have done everything, move the pointers */
  3385.         
  3386.         res++;
  3387.         if ( block ) block++;
  3388.         data += htone->step;
  3389.         l0++, l1++;
  3390.     }
  3391. }
  3392.